How to count corn trees accurately with opencv based on the following image? I have tried HSV conversion with inRange but got nothing so far.
Is there a way for counting the trees correctly? Even with noise reduction I think that it won't count it property.
I chose a template as follows...
and when I tried to run a template match I got the following match..
The match was fine as because I chose the template from that part of the image.However the result image containing the values of the extent of match at different areas of the full image when threshold-ed looked like this..
So you can see that if you count the white patches (neglecting the small noises) you almost get the possible number of crops...!!
EDIT
More precise result you can get if you try the template matching in the green plane of the RGB image
Your problem is easier to solve when implementing few simple preprocessing steps. Look at the result I obtained:
Steps:
Convert RGB to LAB image
Extract A channel (discard L, B channels)
Stretch/Maximize image contrast
Use Otsu's optimal threshold selection for binarization
Invert the image so that foreground is white, background is black
Based on this image template matching or other detection methods should work even better.
Related
This picture is taken by a microscope.
I want to remove the stripes on it. I have tried DFT but it seems these stripes isn't sharp on spectrum domain.
Any advice?
Answer 1: Remove stripe directly from FFT
When I compute the FFT and we got the following image where we can see the stripe signature (I surrounded it in black).
If I remove it by hand I got that:
We can do better be removing only frequency arroud each maximum in cardinal sine.
Answer 2: Segment stripe
process : FFT -> select stripe frequency -> iFFT -> Threshold
The resulting mask contain your stripe. You can substract them from origin image, fill them etc ...
FFT with only stripe :
The resulting mask :
Answer 3: Change Capture process
It seem this stripe come from interference between your microscope slide and your cover slip. You can probably remove it by changing you process.
Solution 1:
Because you only have 3 dominant colors in the image and the stripes color is different from the other objects color, you will probably get the best result by using the objects color and doing a segmentation based on it, for instance using kmeans with k=3 then replace all the pixels that belongs to the darkest cluster with the mean value of the lightest cluster.
Solution 2:
Use hough lines to detect lines in the image,
Find the lightest color in the image,
Draw the lines detected with the lightest color.
Both solutions can be implemented in OpenCV.
Good luck!
Thanks for all the helps above!After some experiment I have implement a method that I assume works well.
Use Fourier first,than apply a filter called tophat to the magnitude image.Than the bright dots will be selected.After remove it from frequency domain, than inverse fft,the stripes will be removed.Then the image need to be filtered to extract the foreground alone.I use Gaussian filter,it works but not perfect.It seems some structure extraction filter exist,such as Relative Total Variation,I'm not sure,if someone have a better idea please tell me.
The image is like thisAfter ifft
Again thanks #Erwan and #Dr.Haimovitz for all the help.
I've been trying to work on an image processing script /OCR that will allow me to extract the letters (using tesseract) from the boxes found in the image below.
Following alot of processing, I was able to get the picture to look like this
In order to remove the noise I inverted the image followed by floodfilling and gaussian blurring to remove noise. This is what I ended up with next.
After running it through some threholding and erosion to remove the noise (erosion being the step that distorted the text) I was able to get the image to look like this before running it through tesseract
This, while a pretty good rendering, allows for fairly accurate results through tesseract. Though it sometimes fails because it reads the hash (#) as a H or W. This leads me to my question!
Is there a way using opencv, skimage, PIL (opencv preferably) I can sharpen this image in order to increase my chances of tesseract properly reading my image? OR Is there a way I can get from the third to final image WITHOUT having to use erosion which ultimately distorted the text in the image.
Any help would be greatly appreciated!
OpenCV does has functions like filter2D that convolves arbitrary kernel with given image. In particular you can use kernels that are used for image sharpening. The main question is whether this will improve the results of your OCR library or not. The image is already pretty sharp and the noise in the image is not a result of blur. I never worked with teseract myself, but I am fairly sure that it already does all the noise reduction it could. And 'helping' him in this process may actually have opposite effect. For example any sharpening process tends to amplify noise (as opposite to noise reduction processes that usually are blurring images). Most of computer vision libraries give better results when provided with raw (unprocessed) images.
Edit (after question update):
There multiple ways to do so. The first one that I would test is this: Your first binary image is pretty clean and sharp. Instead of of using morphological operations that reduce quality of letters switch to filtering contours. Use findContours function to find all contours in the image and store their hierarchy (i.e. which contour is inside which). From all the found contours you actually need only the contours on first and second levels, i.e. outer and inner contours of each letter (contours at zero level are the outermost contours). Other contours can be discarded. Among the contours that do belong to first level you can discard those whose bounding box is too small to be a real letter. After those two discarding procedures I would expect that most of the remaining contours are the ones that are parts of the letters. Draw them on white image and run OCR. (If you want white letters on black background you will need to invert the order of vertices in the contours).
I have a few objects in a black background.I would like to threshold the image and transform the objects in 1 and the black background into 0.
I am not sure how to choose my threshold to isolate the black background.
You can do this simply by the following step.
Load your image.
Convert to gray-scale.
Apply binary threshold which will create the result as your requirement.
Here you can see a good explanation about Basic Thresholding Operations using OpenCV with example.
One of the simplest thing to do is using the OpenCV's threshold function on the whole image and let the threshold value be choosen automatically by means of the Otsu's algorithm (the type argument of the threshold function should be ORed with the constant THRESH_OTSU).
Otsu's original work is: OTSU, Nobuyuki. A threshold selection method from gray-level histograms. Automatica, 1975, 11.285-296: 23-27.
This approach may work very well or it may fail miserably... it depends, as always, on your images.
I have a processed binary image of dimension 300x300. This processed image contains few object(person or vehicle).
I also have another RGB image of the same scene of dimensiion 640x480. It is taken from a different position
note : both cameras are not the same
I can detect objects to some extent in the first image using background subtraction. I want to detect corresponding objects in the 2nd image. I went through opencv functions
getAffineTransform
getPerspectiveTransform
findHomography
estimateRigidTransform
All these functions require corresponding points(coordinates) in two images
In the 1st binary image, I have only the information that an object is present,it does not have features exactly similar to second image(RGB).
I thought conventional feature matching to determine corresponding control points which could be used to estimate the transformation parameters is not feasible because I think I cannot determine and match features from binary and RGB image(am I right??).
If I am wrong, what features could I take, how should I proceed with Feature matching, find corresponding points, estimate the transformation parameters.
The solution which I tried more of Manual marking to estimate transformation parameters(please correct me if I am wrong)
Note : There is no movement of both cameras.
Manually marked rectangles around objects in processed image(binary)
Noted down the coordinates of the rectangles
Manually marked rectangles around objects in 2nd RGB image
Noted down the coordinates of the rectangles
Repeated above steps for different samples of 1st binary and 2nd RGB images
Now that I have some 20 corresponding points, I used them in the function as :
findHomography(src_pts, dst_pts, 0) ;
So once I detect an object in 1st image,
I drew a bounding box around it,
Transform the coordinates of the vertices using the above found transformation,
finally draw a box in 2nd RGB image with transformed coordinates as vertices.
But this doesnt mark the box in 2nd RGB image exactly over the person/object. Instead it is drawn somewhere else. Though I take several sample images of binary and RGB and use several corresponding points to estimate the transformation parameters, it seems that they are not accurate enough..
What are the meaning of CV_RANSAC and CV_LMEDS option, ransacReprojecThreshold and how to use them?
Is my approach good...what should I modify/do to make the registration accurate?
Any alternative approach to be used?
I'm fairly new to OpenCV myself, but my suggestions would be:
Seeing as you have the objects identified in the first image, I shouldn't think it would be hard to get keypoints and extract features? (or maybe you have this already?)
Identify features in the 2nd image
Match the features using OpenCV FlannBasedMatcher or similar
Highlight matching features in 2nd image or whatever you want to do.
I'd hope that because all your features in the first image should be positives (you know they are the features you want), then it'll be relatively straight forward to get accurate matches.
Like I said, I'm new to this so the ideas may need some elaboration.
It might be a little late to answer this and the asker might not see this, but if the 1st image is originally a grayscale then this could be done:
1.) 2nd image ----> grayscale ------> gray2ndimg
2.) Point to Point correspondences b/w gray1stimg and gray2ndimg by matching features.
What's the best set of image preprocessing operations to apply to images for text recognition in EmguCV?
I've included two sample images here.
Applying a low or high pass filter won't be suitable, as the text may be of any size. I've tried median and bilateral filters, but they don't seem to affect the image much.
The ideal result would be a binary image with all the text white, and most of the rest black. This image would then be sent to the OCR engine.
Thanks
There's nothing like the best set. Keep in mind that digital images can be acquired by different capture devices and each device can embed its own preprocessing system (filters) and other characteristics that can drastically change the image and even add noises to them. So every case would have to be treated (preprocessed) differently.
However, there are commmon operations that can be used to improve the detection, for instance, a very basic one would be to convert the image to grayscale and apply a threshold to binarize the image. Another technique I've used before is the bounding box, which allows you to detect the text region. To remove noises from images you might be interested in erode/dilate operations. I demonstrate some of these operations on this post.
Also, there are other interesting posts about OCR and OpenCV that you should take a look:
Simple Digit Recognition OCR in OpenCV-Python
Basic OCR in OpenCV
Now, just to show you a simple approach that can be used with your sample image, this is the result of inverting the color and applying a threshold:
cv::Mat new_img = cv::imread(argv[1]);
cv::bitwise_not(new_img, new_img);
double thres = 100;
double color = 255;
cv::threshold(new_img, new_img, thres, color, CV_THRESH_BINARY);
cv::imwrite("inv_thres.png", new_img);
Try morphological image processing. Have a look at this. However, it works only on binary images - so you will have to binarize the image( threshold?). Although, it is simple, it is dependent on font size, so one structure element will not work for all font sizes. If you want a generic solution, there are a number of papers for text detection in images - A search of this term in google scholar should provide you with some useful publications.