How can i analyze width and length of multiple plant pods in single image using ImageJ software? - imagej

Ihave tried to analyze the images of plant pods using ImageJ software but it does not show the width and length of a pod/pods accurately. Because the pods are curved, it gives the width of a pod upto 5 to 8 cm which should be below 1 cm. Can anyone suggest me exactly how we can measure the width and length of only black portions ?

Please provide a reference scale. Without it, your results will be in pixels not cm or mm!
The rightmost pod results in the following values:
OrthoMedial-Distances (widths)
Mean = 52.65±8.39px;
Median = 55.97px;
MinMax = (10.5, 61.5)px;
Medial-Axis
Length = 1785.0px;
EDIT:
The analysis was done using the ImageJ-plugins "Easy_EdgeTrace.class" for tracing and and "general_TraceDistances.class" for the width and length evaluation. Both can be accessed from here.
Make sure the pods are suitably oriented. The tracing won't work properly for pod #3.
Here is what I get for the rightmost pod:
Here are the widths:
OrthoMedial-Distances (widths):
Mean = 0.69±0.11cm;
Median = 0.73cm;
MinMax = (0.13, 0.81)cm;
Medial-Axis:
Length = 23.90cm;

Related

Detect handwritten characters bounded by a box with OpenCV

I am trying to read a handwritten form which has boxed-input.
I have run tesseract on the image but get strange results. In my understanding, I suppose the best thing to do is to detect the bounding box and minus that from the image. What's the best way to detect the box (semi-box around the character). I tried cv2.HoughLines(), but with no result.
I am new to OpenCV. It will be really helpful if someone can help me out here.
Thanks for your idea. I just realized probably i can look at counting the vertical pixels and greater than certain threshold
def get_pixel_count_in_col(img,col):
count=0
for j in range(img.shape[0]):
if(img[j,col]<255):
count=count+1
return count
def cleanup_img(img):
foundlines=[]
for i in range(img.shape[1]):
if(get_pixel_count_in_col(img,i)>img.shape[0]*0.7):
foundlines.append(i)
if(get_pixel_count_in_col(img,i-1)>img.shape[0]*0.25):
foundlines.append(i-1)
if(get_pixel_count_in_col(img,i+1)>img.shape[0]*0.25):
foundlines.append(i+1)
return np.delete(img,foundlines,1)
The resulting image makes more sense. But is there any other easy way to do this ?
It seems that your input format is quite clean and consistent. You can simply hard-code the width of each box in pixels and crop out the characters. However if the input format is not fixed then we can extend this answer to handle that as well(it would be bit expensive), so as the first attempt we would simply go with hard coding the width of boxes in pixels.
def get_image_chunks(img, size):
chunks = []
# To remove black borders
padding = 2
for i in xrange(0, img.shape[1], size):
col_start = i + padding
col_end = i + size - padding
# Slicing the numpy array.
chunks.append(img[:-padding, col_start:col_end])
return chunks
img = cv2.imread("/Users/anmoluppal/Downloads/GLUmJ.jpg", 0)
chunks = get_image_chunks(img, 42)
Outputs:
;
;

JPEG2000 : Can number of tiles in X direction be zero?

According to JPEG2000 specs, Number of tiles in X and Y directions is calculated by following formula:
numXtiles =  (Xsiz − XTOsiz)/ XTsiz
&
numYtiles =  (Ysiz − YTOsiz)/ YTsiz
But it is not mentioned about the range of numXtiles or numYtiles.
Can we have numXtiles=0 while numYtiles=250 (or any other value) ?
In short, no. You will always need at least one row and one column of tiles to place your image in the canvas.
In particular, the SIZ marker of the JPEG 2000 stream syntax does not directly define the number of tiles, but rather the size of each tile. Since the tile width and height are defined to be larger than 0 (see page 453 of "JPEG 2000 Image compression fundamentals, standards and practice", by David Taubman and Michael Marcellin), you will always have at least one tile.
That said, depending on the particular implementation that you are using, there may be a parameter numXtiles that you can set to 0 without crashing your program. In that case, the parameter is most likely being ignored or interpreted differently.

How to classify images based on the amount of colors in the image?

I have a problem where all images have the same object; however, these objects can either have number_of_colors<=3 OR number_of_colors>3 and images are not labeled.
My attempt starts by converting RGB to LAB and Consider only the A & B to find the color coverage of that image. I was thinking of it as an area on the AB space. So for every image, I found the range of A and B (i.e max(A)-min(A), max(B)-min(B)) and multiplied them together to get the area, assuming it's a rectangle. Then I threshold using this feature.
Please let me know if intuition is correct and why it isn't working. Here is the confusion matrix:
TP: 0.41935483871, FN: 0.0645161290323
FP: 0.0967741935484, TN: 0.41935483871
Here is the basic routine the should work per image
LAB = rgb_to_lab(data_rgb[...,0],data_rgb[...,1],data_rgb[...,2])
A = LAB[1]
B = LAB[2]
minA,maxA = np.min(A),np.max(A)
minB,maxB = np.min(B),np.max(B)
diff_A = maxA - minA
diff_B = maxB - minB
area = diff_A * diff_B
# p is the normalized area
p = area/(200*200.)
# Found 0.53 to be the best possible threshold
if p >0.53:
print 'class 1 - colors > 3'
else:
print 'class 2 - colors <= 3'
Edit 1:
Here is an image to show how the threshold separates positive and negative images
Edit 2:
This shows the same plot but only considering A and B values with luminance between 16 and 70 which seems to increase the area of separation reduces the FP by 1.

Why does the Sobel function for edge detection fail to find the contour of a white square in a black background?

I tryed to apply to the image the following code in octave:
sq = imread("Square BW.jpg");
figure(1), imshow(Square);
cont1 = edge(sq,"Sobel");
figure(2), imshow(cont1);
The image I get is:
And a similar image appears if I use the Prewitt function. Can anyone explain to me what is happening? The problem is that I can't visualize the process only the result, so I can't understand why the code isn't working.
The problem seems to be how threshold is computed in Octave. You can see how Octave does it by looking at its source by entering type edge at the Octave prompt, or online (I'm not copying the exact code since the code is GPL -- although quite simple)
To get the border, you will need to set the threshold yourself (hopefully, in future versions of Octave's image package this will be fixed but at the moment it's Matlab incompatible since Matlab documentation on their default is unclear).
There's definitely a problem with the way the threshold is computed, however I wasn't able to find the correct value to use in this picture. After many attempts I found this code that seems to work perfectly:
sq = imread("Square BW.jpg");
maskSobel = fspecial("sobel");
mSobel = uint8(zeros(size(BW)));
for i = 0:3
mSobel += imfilter(sq, rot90(maskSobel, i));
end
figure(1), imshow(mSobel);
First we create the Sobel matrix/operator and a zero matrix the same size of the image Square BW. Then we rotate the Sobel matrix four times (by 90 degrees), in order filter the image in all directions (left-right, up-down, right-left and down-up), always adding the result to the mSobel matrix that was created.
Here's the final result:

Changing widthstep of image opencv

I am working on project related to face recognition. For my program to work each image should satisfy the condition img->widthStep = 3 * img->width.
I am trying my code on database in which each image is of size 250x250. But the widthstep for the database is 752 hence the above condition does not satisfy. The function of widthstep is in accessing the pixel (http://opencv-users.1802565.n2.nabble.com/What-is-widthstep-td2679559.html).
Can I change the widthstep parameter to 750 without affecting other parameters of image?
Or else is there other way to achieve the condition zimg->widthStep = 3 * img->widthz?
I tried copying the 250x250 to 260x260 image as follows
Mat img1, img2=Mat::zeros(Size(260,260),CV_8UC3);
img1 = imread(ch);
img1.copyTo(img2.colRange(1,250).rowRange(1,250));
But it shows this error:
OpenCV Error: Assertion failed
(!fixedSize() || ((Mat*)obj)->size.operator()() =
= Size(cols, rows)) in unknown function, file D:\opencv2.4.5\opencv\modules\core
\src\matrix.cpp, line 1372
Can anyone help me out.
Thank you!
Since you are using term widthStep I guess you are using IplImage. IplImage was taken from Intel Performance Primitives (IPP) library. In order to have good performance it is required that widthStep of each row should be multiple of 4. To enforce this condition rows are padded with addition bytes. So as long as you are using IplImage you won't be able to have widthStep equal to 750 which is not multiple of 4.
OpenCV 1 was based on IplImage, but OpenCV 2 is based on Mat. Its been a years since IplImage was deprecated.
Mat has no such limitation. By default its step will be 750.
After edit of the question:
colRange(1,250) means 249 columns, not 250. Same for rowRange(1,250). When size of the image being copied is different from size of target image, target image is reallocated. But since colRange and rowRange return constant temporary image it can't be reallocated and the program crashes.

Resources