Process engraved text for OCR - python-3.x

I am working on these images to read the VIN number from the bottom of the car.
Before i proceed with the OCR, i am trying to process the images some how.
image = cv2.imread(imgpath)
# Convert To gray scale
imagegray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Edge Detection since it is engraved
high_thresh, thresh_im = cv2.threshold(imagegray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
low_thresh = 0.5*high_thresh
imagecanny = cv2.Canny(imagegray, low_thresh, high_thresh)
# Dilation
kernel = np.ones((2,2),np.uint8)
imagedilated = cv2.dilate(imagecanny, kernel, iterations = 1)
kernel = np.ones((2,2),np.uint8)
imageeroded = cv2.erode(imagedilated, kernel, iterations = 1)
And this is what i have so far.
There are additional challenges in the images that i have, such as:-
Not all the images are having horizontal orientation -- Skew is present. Any idea how can i fix that?
Some engravings are deep while some are shallow, How can deal with that?
Assume that these images were being taken from a photo camera.
I am bit of a newbie in this field. Any help would be appreciated.Thanks

I don't deal with graphics but perhaps I can say at least something. I downloaded your pics and tried to adjust the colors in your image manually in my favourite photo editor. To make the text even, I applied grayscale and played with Gamma correction and Contrast. It gave me nothing until I cropped the images to a narrow strip, like this:
After this, adjustments work much better. Therefore my advice would be to require as little graphic data as possible to avoid such interference. And you will probably want to check out some fonts that are used by various manufacturers, since here I can see different fonts. If there's not much choice, you can generate those fonts for yourself.

Related

Smoothing the edges of segmented images

I am working on breast region segmentation using Huang Thresholding. The original and result image is provided here:
As you can see the mask edges are not smooth enough but it's accepted in this sample. Next is another sample with the mask edges pretty jagged:
In the attached picture I already implemented some preprocessing to smoothing the edge by using close operation with the following codes (I tried it with the median filter but not much effect).
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
closed = cv2.morphologyEx(canvas.copy(), cv2.MORPH_CLOSE, kernel, iterations=3)
I also tried the solution provided here:
but not satisfying enough for me in this case.
Can anybody help me or suggest me a method to smooth the edges of the mask? Here I have provided the mask images for sample1:
and for sample2:
.
FYI, I planned to bitwise_and the image with the mask so I can remove the background images. Background images in mammograms sometimes not really black background and contain too much noise which you don't want when enhancing the image after.
`

crop images with different black margins

I have an image dataset and before feeds it to deep learning algorithm I need to crop it to the same size. All images have different size of black margins as the below image demonstrates.
Any suggestions for a way to crop images with different margin size.
Since your border color is black (nearly perfect black) and will be the same in all the images, I would suggest applying binary threshold making everything white (255) except the black region. Now some of the image regions may get affected too but that's not a problem.
Now find contours in the image and second largest contour will be your region. Calculate rectangular bounding box for this contour and crop the same region in the original image.
First, do a thresholding with a low-intensity threshold value (if your background is definitely completely black, you could even threshold at an intensity of 1) to determine all non-border components.
Next, use Connected-component labeling to determine all isolated foreground components. The central scan-image you are interested in should then always result in the biggest component. Crop out this biggest component to remove the border together with all possible non-black artifacts (labels, letters etc.). You should be left with only the borderless scan.
You can find all the algorithms needed in any basic image processing library. I'd personally recommend looking into OpenCV, they also include phyton bindings.
One way to this could be as follows:
Flood-fill the image with red starting at the top-left corner, and allowing around 5% divergence from the black pixel there.
Now make everything that is not red into white - because the next step after this looks for white pixels.
Now use findContours() (which looks for white objects) and choose the largest white contour as your image and crop to that.
You could consider making things more robust by considering some of the following ideas:
You could normalise a copy of the image to the full range of black to white first in case you get any with near-black borders.
You could check that more than one, or all corner pixels are actually black in case you get images without a border.
You could also flag up issues if your cropped image appears to be less than, say 70%, of the total image area.
You could consider a morphological opening with 9x9 square structuring element as the penultimate step to tidy things up before findContrours().
here is the solution code for this question:
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
import cv2
import numpy as np
import os
path = "data/benign/"
img_resized_dir = "data/pre-processed/benign/"
dirs = os.listdir(path)
def thyroid_scale():
for item in dirs:
if os.path.isfile(path+item):
img = cv2.imread(path+item)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,0,255,0)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
crop_img = img[y+35:y+h-5,x+25:x+w-10]
resize_img = cv2.resize(crop_img, (300, 250), interpolation = cv2.INTER_CUBIC)
cv2.imwrite(img_resized_dir+item, resize_img)
thyroid_scale()

Otsu's method thresholding making a 'shroud'

I'm trying to threshold an image using Otsu's method in Opencv:
Although when I threshold it, some parts of the picture are completely surrounded by white and creates and ends up in Opencv not detecting all the contours in the image. This is what I get when I do Otsu's method thresholding usingret,thresh=cv2.threshold(blurred,0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU):
EDIT:
Some people have asked for the code I am using so here it is:
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv2.imshow('Input Image', image)
cv2.waitKey(0)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY_INV,81,2)
#ret, thresh = cv2.threshold(blurred,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
#thresh_value = 70
#ret,thresh= cv2.threshold(blurred,thresh_value,255,cv2.THRESH_BINARY)
Now it makes some checkered noise:
You do not need to manually find a sweet spot! Let OpenCV do it for you!
OpenCV has an adaptive thresholding algorithm exactly from problems like this, called adaptiveThreshold
This function divides the image into multiple sub-images, and thresholds each one individually. This means that it will find a nice threshold value for each part of the image and give you a nice and uniformly lit image. See this example.
Try this:
th3 = cv.adaptiveThreshold(blurred,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv.THRESH_BINARY,11,2)
Update:
Functions like these do not work perfectly out of the box. If it still creates artefacts like salt and pepper noise, you can try:
Significantly increasing the blockSize. This can ensure that each block has a letter inside, which will hopefully mean the threshold will be chosen better. (e.g. Dividing the image into 25 blocks instead of 100. A blocksize of 11 pixels is very small.)
First apply a blurring filter to ease out the bad spots creating the seasoning noise. (With the image name blurry I imagine that you've done this already.
First the simple threshold function to just removes some noise. For example setting all pixels above 5 and below 100 equal to zero. Then after that apply the adaptiveThreshold.
Follow #Mark`s advice by subtracting a blurred image from the original image. (See this thread)
I hope this helps!
Instead of using Otsu's method try global thresholding method.
thresh_value = 50
ret,thresh= cv2.threshold(blurred,thresh_value,255,cv2.THRESH_BINARY)
change the thresh_value parameter until you get the result you want.
Get to know more about thresholding techniques please refer the documentation.

Reducing / Enhancing known features in an image

I am microbiology student new to computer vision, so any help will be extremely appreciated.
This question involves microscope images that I am trying to analyze. The goal I am trying to accomplish is to count bacteria in an image but I need to pre-process the image first to enhance any bacteria that are not fluorescing very brightly. I have thought about using several different techniques like enhancing the contrast or sharpening the image but it isn't exactly what I need.
I want to reduce the noise(black spaces) to 0's on the RBG scale and enhance the green spaces. I originally was writing a for loop in OpenCV with threshold limits to change each pixel but I know that there is a better way.
Here is an example that I did in photo shop of the original image vs what I want.
Original Image and enhanced Image.
I need to learn to do this in a python environment so that I can automate this process. As I said I am new but I am familiar with python's OpenCV, mahotas, numpy etc. so I am not exactly attached to a particular package. I am also very new to these techniques so I am open to even if you just point me in the right direction.
Thanks!
You can have a look at histogram equalization. This would emphasize the green and reduce the black range. There is an OpenCV tutorial here. Afterwards you can experiment with different thresholding mechanisms that best yields the bacteria.
Use TensorFlow:
create your own dataset with images of bacteria and their positions stored in accompanying text files (the bigger the dataset the better).
Create a positive and negative set of images
update default TensorFlow example with your images
make sure you have a bunch of convolution layers.
train and test.
TensorFlow is perfect for such tasks and you don't need to worry about different intensity levels.
I initially tried histogram equalization but did not get the desired results. So I used adaptive threshold using the mean filter:
th = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 3, 2)
Then I applied the median filter:
median = cv2.medianBlur(th, 5)
Finally I applied morphological closing with the ellipse kernel:
k1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
dilate = cv2.morphologyEx(median, cv2.MORPH_CLOSE, k1, 3)
THIS PAGE will help you modify this result however you want.

How do we remove illumination noise?

I have a car detecting project in OpenCV2.3.1 and visual C++.
In foreground segmentation, there's reflections due to illumination.
And this (reflections) become part of the foreground after the background
has been removed.
I need suggestions or ideas on how to remove this noise. As it causes some
foreground objects to be connected up as one object, like seen when using
findContours and drawContours functions. See image parts highlighted in red
on attached image. I think this will simplify the blob detection stage.
*note - I am not allowed to use built-in cvBlobLib in OpenCV
Issue here is that part of a glare can be either background or corresponding car.
Here is what I would do.
I believe you would not have a big problem with identifying glare parts by binarizing and thresholding or in a similar way.
Once identified all pixels of glares, I would replace each of the glare pixels with nearest non-glare pixel in the same row of the image. That way, a glare will be filled with car and background. With this method, then you would be able to detect cars without much problem.
maybe try to convert the image to HSV then filter high V amounts
IplImage imgHSV = cvCreateImage(cvGetSize(imgInput), 8, 3);
IplImage imgThreshold = cvCreateImage(cvGetSize(imgHSV), 8, 1);
cvInRangeS(imgHSV, cvScalar(0, 0, 90, 0), cvScalar(0, 0, 100, 0), imgThreshold);
..adjust scalars as needed to remove glare

Resources