Zero padding / median filtering - image-processing

I'm trying to implement median filtering using image j .
I am having trouble with the zero padding as it adds extra zeros to the bottom and far left of the picture.
This is what I have done so far, if you guys can help me out:
Dialog.create("9x9 median filtering");
Dialog.addMessage("9x9 median filtering");
Dialog.show();
setBatchMode(true);
median_filter_9();
setBatchMode("exit and display");
// Produce the 9x9 median image
function median_filter_9()
{
width = getWidth();
height= getHeight();
//if you want to apply this median filter to 16bit
depth = bitDepth();
nBin= pow(2, depth);
//nBin hold max gray intensity value
filteHisto = newArray(nBin);
//filteHisto = newArray(255);
fiveBYFive = newArray(81);
//this is what i used for middle position of array to get median
middlePos = round(81/2);
//-3, -3 will get you position 0,0 of a 9x9 matrix if you start in the middle
for(j=-2;j<width-2;j++){
for(i=-2;i<height-2;i++){
z=0;
for(r=0;r<9;r++){
for(c=0;c<9;c++){
//Extend outside image boundaries using zero padding.
//error here: adds extra to bottom and farleft of picture
if(j+r<0||j+r>=width||i+c<0||i+c>=height){
fiveBYFive[z]=0;
z++;
}else{
v = getPixel(j+r,i+c);
fiveBYFive[z]= v;
z++;
}
}
}
//sort the array to find median
Array.sort(fiveBYFive);
median = fiveBYFive[middlePos];
setPixel(j, i, median);
}
updateDisplay();
}
}

One problem you're seeing at the edges of your image is because you are padding your 9x9 window with zeroes ok, but you still take the median value as the middle of the 81 item window.
So, for example, in the first column of the image, you zero-pad at least 36 elements (more at the top and bottom), which means that you only need to find 4 or 5 more zero pixels in the image to make the median element zero.
The easiest fix is to adjust your median element's index (initialised to 81/2 on each iteration) upward according to how many zeroes you added, or just count how many non-zero pixels you used and then find the median mid-way through that range in your sorted array (taking account of sort order).
In this way, you take the median value of the actual pixels you found and ignore the padded zeroes.
Probably, you missed changing your code from the original 5x5 to 9x9, because the start/end indices are in any case wrong and should be
for(j=-4;j<width;j++){
for(i=-4;i<height;i++){
The other possible source of confusion later is with this line, where it looks like you've confused width and height
if(j+r<0||j+r>=width||i+c<0||i+c>=height)
If j is the column index and i is the row index, it should be
if(j+c<0||j+c>=width||i+r<0||i+r>=height)
Although for a square window this doesn't actually make any difference in practice.

Related

Why .width() and .height() modifiers apply wrong value?

I want two independent rows to have the same width and scroll simultaneously. I have tried to achieve this in this way:
#Composable
fun TwoRows() {
val scrollState = rememberScrollState()
Column(Modifier.fillMaxWidth()) {
Row(Modifier.fillMaxWidth().horizontalScroll(scrollState)) {
for (i in 0 until 100) {
Box(Modifier.width(10.dp).height(10.dp).background(Color.Red))
Spacer(Modifier.width(90.dp))
}
}
Row(Modifier.fillMaxWidth().horizontalScroll(scrollState)) {
for (i in 0 until 100) {
Box(Modifier.width(100.dp).height(10.dp).background(Color.Green))
}
}
}
}
The first row consists of 10 dp width red rectangles and 90 dp width spacers. The second row consists of only 100 dp width green rectangles. I'm expecting these rows to have the same width but the layout inspector shows they're not:
Because of this the elements do not match expecting positions:
How can I fix it?
This is happening because each of .size(), width(), .height() modifiers transform incoming value into pixel just in time it applied. I.e. they apply independently - the first modifier converts its value to pixels, and then the second, and so on. There is no guarantee that you get the same dp value after transforming it to px and back because of rounding. Here is how dp->px->dp transformation works for your case:
dp = 10.dp // Incoming dp value
density = 2.625 // Screen density scale value of your emulator
unrounded_px = 10 * density = 26.25
px = 26
restored_dp = 26 / density = 9.904762.dp
Most likely that the LayoutInspector doesn't round computed dp value to the nearest integer, but simply discards the fractional part. I think this is the reason why it shows different value. Such behavior is especially likely to occur when you work with relatively small views on low pixel density screens.
You can achieve desired behavior wrapping your red Box and Spacer into the Box with specified size:
Box(Modifier.width(100.dp).height(10.dp)) {
Box(Modifier.width(10.dp).height(10.dp).background(Color.Red))
Spacer(Modifier.width(90.dp))
}

Emgu CV:using HoughCircles detect many nonexistent circles,and waiting for long time

original picture
result picture
Here is my code:
private void button3_Click(object sender, EventArgs e)
{
string strFileName = string.Empty;
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == DialogResult.OK)
{
Image<Bgr, byte> img1 = new Image<Bgr, byte>(ofd.FileName);
pictureBox1.Image = img1.ToBitmap();
Image<Gray, Byte> gray1 = img1.Convert<Gray, Byte>().PyrUp().PyrDown();
CircleF[] circles = gray1.HoughCircles(
new Gray(150),
new Gray(100),
2,
10,
0,
0)[0];
Image<Bgr, byte> imageCircles = img1.CopyBlank();
foreach (CircleF circle in circles)
{
imageCircles.Draw(circle, new Bgr(Color.Yellow), 5);
}
pictureBox4.Image = imageCircles.ToBitmap();
}
}
Are my parameters set correctly? Is there something I'm not understanding correctly?
Thank you!
EmguCV wraps the OpenCV stuff, so you can get mor information about how to use Emgu methods by looking at the OpenCV Doku. Here is he Hough transformation explained (could be that the parameter count or order varies but in most cases the parameter names match. At the explanation point 4 (Proceed to apply Hough Circle Transform:) you get all parameters explained:
dp = 1: The inverse ratio of resolution
min_dist = src_gray.rows/8: Minimum distance between detected centers
param_1 = 200: Upper threshold for the internal Canny edge detector
param_2 = 100*: Threshold for center detection.
min_radius = 0: Minimum radio to be detected. If unknown, put zero as default.
max_radius = 0: Maximum radius to be detected. If unknown, put zero as default
According to the Emgu Doku these values are used:
cannyThreshold
Type: TColor
The higher threshold of the two passed to Canny edge detector (the lower one will be twice smaller).
accumulatorThreshold
Type: TColor
Accumulator threshold at the center detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first
dp
Type: SystemDouble
Resolution of the accumulator used to detect centers of the circles. For example, if it is 1, the accumulator will have the same resolution as the input image, if it is 2 - accumulator will have twice smaller width and height, etc
minDist
Type: SystemDouble
Minimum distance between centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed
minRadius (Optional)
Type: SystemInt32
Minimal radius of the circles to search for
maxRadius (Optional)
Type: SystemInt32
Maximal radius of the circles to search for
So try to use a higher accumulatorThreshold (like 150 or 180) because your circles are pretty obvious. On large images a higher dp could help too, decreasing your waiting time.
Your dp is 10 ( I think it means 10pixils between detected centers) just take a much higher number depending on your image size. the OpenCV example uses an 8th of images height.
A minRadius of 0 should be ok since your image shows only large (yellow) circles.
A max Radios should depend on your image size too - this would remove those really large circles in lower image part.
Just try 5% of your image height as minRadius and ca 90% as maxRadius - or simply use sliders and an apply button to try it yourself

How can i prevent my object detection program from detecting multiple objects of different sizes?

So, here is my situation. I have created a object detection program which is based on color object detection. My program detects the color red and it works perfectly. But here is the problems i am facing:-
Whenever there are more than one red object in the surrounding, my program detects them and it cannot really track one object at that time(i.e it tracks other red objects of various sizes in the background. It shows me the error that "too much noise in the background". As you can see in the "threshold image" attached, it detects the round object (which is my tracking object) and my cap which is red in color. I want my program to detect only my tracking object("which is a round shaped coke cap"). How can i achieve that? Please help me out. I have my engineering design contest in few days and i have to demo my program infront of my lecturers. My program should only be able to detect and track the object which i want. Thanks
My code for the objectdetection program is a little long. So, i am hereby explaining the code as follows- I captured a frame from the webcam frame-converted it to HSV- used HSV Inrange filter to filter out the other colors but red- applied morphological operations on the filtered image. This all goes in my main function
I am using a frame resolution of 1280*720 for my webcam frame. It kind of slows down my program but it was a trade off which i had to do for performing gesture controlled operations. Anyways here is my drawobjectfunction and trackfilteredobjectfunction.
int H_MIN = 0;
int H_MAX = 256;
int S_MIN = 0;
int S_MAX = 256;
int V_MIN = 0;
int V_MAX = 256;
//default capture width and height
const int FRAME_WIDTH = 1280;
const int FRAME_HEIGHT = 720;
//max number of objects to be detected in frame
const int MAX_NUM_OBJECTS=50;
//minimum and maximum object area
const int MIN_OBJECT_AREA = 20*20;
const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5;
void drawObject(int x, int y,Mat &frame){
circle(frame,Point(x,y),20,Scalar(0,255,0),2);
if(y-25>0)
line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2);
if(y+25<FRAME_HEIGHT)
line(frame,Point(x,y),Point(x,y+25),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(x,FRAME_HEIGHT),Scalar(0,255,0),2);
if(x-25>0)
line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2);
if(x+25<FRAME_WIDTH)
line(frame,Point(x,y),Point(x+25,y),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(FRAME_WIDTH,y),Scalar(0,255,0),2);
putText(frame,intToString(x)+","+intToString(y),Point(x,y+30),1,1,Scalar(0,255,0),2);
}
void trackFilteredObject(int &x, int &y, Mat threshold, Mat &cameraFeed){
Mat temp;
threshold.copyTo(temp);
//these two vectors needed for output of findContours
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
//find contours of filtered image using openCV findContours function
findContours(temp,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );
//use moments method to find our filtered object
double refArea = 0;
bool objectFound = false;
if (hierarchy.size() > 0) {
int numObjects = hierarchy.size();
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if(numObjects<MAX_NUM_OBJECTS){
for (int index = 0; index >= 0; index = hierarchy[index][0]) {
Moments moment = moments((cv::Mat)contours[index]);
double area = moment.m00;
//if the area is less than 20 px by 20px then it is probably just noise
//if the area is the same as the 3/2 of the image size, probably just a bad filter
//we only want the object with the largest area so we safe a reference area each
//iteration and compare it to the area in the next iteration.
if(area>MIN_OBJECT_AREA && area<MAX_OBJECT_AREA && area>refArea){
x = moment.m10/area;
y = moment.m01/area;
objectFound = true;
refArea = area;
}else objectFound = false;
}
//let user know you found an object
if(objectFound ==true){
putText(cameraFeed,"Tracking Object",Point(0,50),2,1,Scalar(0,255,0),2);
//draw object location on screen
drawObject(x,y,cameraFeed);}
}else putText(cameraFeed,"TOO MUCH NOISE! ADJUST FILTER",Point(0,50),1,2,Scalar(0,0,255),2);
}
}
Here is the link of the image; as you can see it also detects the red hat in the background along with the red cap of the coke bottle.
My observations:- Here is what i think, to achieve my desired goal of not detecting objects of unknown sizes of red color. I think i have to edit the value of maximum object area which i declared in the above program as (const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5;). I think i have to change this value, that might eliminate the detection of bigger continous red pictures. But also, there is another problem some objects are not completely red in color and they have patches of red and other colors. So, if the detected area is within the range specfied in my program then my program detects those red patches too. What i mean to say is i was wearing a tshirt which has mixed colors and when i tested my program by wearing that tshirt, my program was able to detect the red color out of the other colors. Now, how do i solve this issue?
I think you can try out the following procedure:
obtain a circular kernel having roughly the same area as your object of interest. You can do it like: Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(d, d));
where d is the diameter of the disk.
perform normalized-cross-correlation or convolution of the filtered regions image with this kernel (I think normalized-cross-correlation would be better. And add an empty boarder around the kernel).
the peak of the resulting image should give you the location of the circular region in your filtered image (if you are using normalized-cross-correlation, you'll have to add the shift).
To speed things up, you can perform this at a reduced resolution.
You can filter out non-circular shapes by detecting circles in your thresholded image. OpenCV provides a built-on method to detect circles using Hough transform, more info here. You can take advantage of this function to retain only circles that have a radius in a given range.
Another possibility is to implement connected component labeling (CCL) into your demo program.
I believe that it was removed at some point in verions 2.x of OpenCV, but a basic implementation of the two-pass version is straightforward from the Wikipedia page.
CCL will assign a unique ID for each object after thresholding. You then have to implement matching between the objects at frame (T-1) and objects in frame (T) (for example based on some nearest distance criterion) and possibly trajectory filtering or smoothing, but this would definitely give you some extra-points.

minMaxLoc maximum value confusion

I have been using minMaxLoc to compute the maximum value of the data obtained by running a laplacian filter over a grayscale image. My simple intention is to roughly estimate the sharpness. I encountered a confusing situation, which I have discussed here.
The max value obtained from the minMaxLoc function was like 1360, 1456,450 etc for a set of images.
Laplacian(src_gray,dst,ddepth,kernel_size,scale,delta,BORDER_DEFAULT);
minMaxLoc(dst,&min,&estimate,&minLoc,&maxLoc,noArray());//Estimate is the max value
Now I just tried to compute the average to have a better idea of the spread of the sharpness in the image. Note that DST is the Mat variable holding data from the Laplacian.
Size s = dst.size();
rows = s.height;
cols = s.width;
total = 0;
max = 0;
for(int k=0;k<rows;k++)
{
for(int l=0;l<cols;l++)
{
total = total + abs(dst.at<int>(k,l));
}
}
average = total/(rows*cols);
There are 2 baffling results I obtained. The average value I obtained, was not only greater than the max value obtained from minMaxLoc, but also was at times negative, when tried over a set of images. sample Average values where 22567, at times -25678.
The occurrence of negative was even more baffling as am using the abs() to get the absolute value of the laplacian results.
To get a proper understanding, I calculated the max value by myself and then the average values :
Size s = dst.size();
rows = s.height;
cols = s.width;
total = 0;
max = 0;
for(int k=0;k<rows;k++)
{
for(int l=0;l<cols;l++)
{
if(abs(dst.at<int>(k,l))>max)
{
max = abs(dst.at<int>(k,l));
}
total = total + abs(dst.at<int>(k,l));
}
}
average = total/(rows*cols);
surprisingly, I found the max value to be in 8 digits.
This is why I got confused. What is the max value given from the minMaxLoc function? And why is the abs() in total, not working and why am I getting -ve average values.?
Please forgive me if am missing something in the code, but this is slightly confusing me. Thanks for your help in advance.
I think you should use .at< uchar > instead of int (considering image to be grayscale) otherwise the value will overflow!
Typically images have 8 bit images. So chances are, that you are accessing the pixels of your image using the wrong method. And in this case, the values you read from the matrix are wrong.
To check if you are working with a single channel integer matrix use
dst.type() == CV_32SC1 .
To check for a 8 bit matrix use
dst.type() == CV_8SC1 .
If you are actually having such an 8 bit integer matrix, you need to use .at<uchar> to access the pixels.
The reason your total variable is negative even though you only added positive values to it is probably due to an integer overflow. You can avoid this by using a long int for total.

how to optimized this image processing replace all pixels on image with closest available RGB?

Im' trying to replace all pixels of input image with closest available RGB. I have a array contain color and input image. Here is my code, it give me an output image as expected, BUT it take very LONG time( about a min) to process one image. Can anybody help me improve the code? Or if you have any other suggestions, please help.
UIGraphicsBeginImageContextWithOptions(CGSizeMake(CGImageGetWidth(sourceImage),CGImageGetHeight(sourceImage)), NO, 0.0f);
//Context size I keep as same as original input image size
//Otherwise, the output will be only a partial image
CGContextRef context;
context = UIGraphicsGetCurrentContext();
//This is for flipping up sidedown
CGContextTranslateCTM(context, 0, self.imageViewArea.image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// init vars
float d = 0; // squared error
int idx = 0; // index of palette color
int min = 1000000; // min difference
UIColor *oneRGB; // color at a pixel
UIColor *paletteRGB; // palette color
// visit each output color and determine closest color from palette
for(int y=0; y<sizeY; y++) {
for(int x=0; x<sizeX; x++) {
// desired (avg) color is one pixel of scaled image
oneRGB = [inputImgAvg colorAtPixel:CGPointMake(x,y)];
// find closest color match in palette: init idx with index
// of closest match; keep track of min to find idx
min = 1000000;
idx = 0;
CGContextDrawImage(context,CGRectMake(xx, yy, 1, 1),img);
}
}
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageViewArea.image = output;
This is a similar question (with no definitive answer), but the answer there has the code for directly accessing pixels from an image.
Quantize Image, Save List of Remaining Colors
You should do that rather than use CG functions for each get and set pixel. Drawing 1 pixel of an image onto another image is a lot slower than changing 3 bytes in a array.
Also, what's in ColorDiff -- you don't need perfect diffing as long as the closest pixel has the smallest diff. There may be room for pre-processing this list so that for each palette entry you have the smallest diff to the nearest other palette entry. Then, while looping through pixels, I can quickly check to see if the next pixel is within half that distance to the color just found (because photos tend to have common colors near each other).
If that's not a match, then while looping through the palette, if I am within half this distance to any entry, there is no need to check further.
Basically, this puts a zone around each palette entry where you know for sure that this one is the closest.
The usual answer is to use a k-d tree or some other Octree structure to reduce the number of computations and comparisons that have to be done at each pixel.
I've also had success with partitioning the color space into a regular grid and keeping a list of possible closest matches for each part of the grid. For example you can divide the (0-255) values of R,G,B by 16 and end up with a grid of (16,16,16) or 4096 elements altogether. Best case is that there's only one member of the list for a particular grid element and no need to traverse the list at all.

Resources