Tesseract OCR failed to identify some characters - c++

I'm working on a c++ project where I need to OCR some text fields. I'm using Tesseract version 3.02 c++ API functions to achieve this. But the OCR results differ from the image.
The following image reads as "31 SW19 SQU" when i use api.GetUTF8Text() function.
and the following image as "31 SW19 3OU".
One problem is tesseract identifies the first character as "3" and fails to identify it within "3QU" correctly.
Can someone explain to me why the tesseract fails to identify these images or any guidance to fix the issue.

I screen grabbed that image and ran it through my setup (v5.0.0 alpha) and it got it right for me:
def TestImage2String(file):
img = cv2.imread(file)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
gray, th = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)
out = pytesseract.image_to_string(th)
print(out)
The output was:
SW19 3QU
It's Python, but the c++ API is very similar.

Related

Threshold function does not work OpenCV C++

I just want to do convert a gray image to a binary image. But threshold function gives me a totaly black image as a binary image. I want to get dark gray object.
What is wrong here?
Code:
Mat theFrame = imread("C:\\asdsss.png"); // opencv
Mat gray,binary;
cvtColor(theFrame, gray, CV_BGR2GRAY);
threshold(gray, binary, 150, 255, THRESH_BINARY);
imwrite("result.jpg",binary);
İnput image:
The code works perfectly fine. I ran you exact code on the image provided. There is no issue with it.
I got the following output by running your code. The only problem I can think of could be loading of image. Try to see your image using cv::imshow after loading it. Also try to convert your image into jpg format and then try loading it again. You can also try compiling and running the opencv thresholding sample.

C++ loading and looping through pixels of an image (JPEG format)

Hello there and thank you for at the very least, trying to help me.
I need to, firstly, load an image and then loop through all pixels of that image and check the color of each pixel.
I have never tried messing around with images or whatnot.
Any help is greatly appreciated.
Thank you.
Looking at the bigger picture, of counting the dots on a dice, I would look at using ImageMagick - with the C++ binding called Magick++ from here
I would be looking at using "Blob Analysis", or "Connected Component Analysis" to count the dots on a dice.
Using this dice...
If I use ImageMagick at the command line like this:
convert dice.png -colorspace gray -threshold 50% \
-define connected-components:verbose=true \
-define connected-components:area-threshold=10 \
-connected-components 8 -auto-level output.png
Output
Objects (id: bounding-box centroid area mean-color):
0: 380x362+0+0 189.6,180.0 103867 srgba(255,255,255,1)
2: 93x92+248+32 293.8,77.5 6743 srgba(0,0,0,1)
4: 92x93+39+241 84.8,286.7 6741 srgba(0,0,0,1)
5: 93x93+248+241 293.8,286.8 6738 srgba(0,0,0,1)
1: 92x92+39+32 84.8,77.5 6736 srgba(0,0,0,1)
3: 93x93+143+136 189.3,182.1 6735 srgba(0,0,0,1)
You can see it has found 5 dots (the first one is actually the whole, white image), and I can put a red box around each dot like this so you can see what it has found:
convert dice.png -stroke red -fill none -strokewidth 1 -draw "rectangle 248,32 341,124" -draw "rectangle 39,241 131,334" -draw "rectangle 248,241 341,334" -draw "rectangle 39,32 131,124" -draw "rectangle 143,136 236,229" result.png
I think you may use OpenCV image processing library. You have a detailed manual for installing for VS2013 here:
OpenCV installation for Visual Studio 2013
After you've installed it. You will get a lot of functions for image processing, including what you are looking for.
For example:
Mat inputImage = imread(filename, CV_LOAD_IMAGE_COLOR);
then:
Cycle through pixels with opencv
One of the methods you could use, is to interpret the file as binary. If you know how to interpret the header part and know what color depth the image has (the header has such info), then it wont be a longshot to just compare binary or hexadecimal color codes - probably hexadecimal since C++ doesnt have a built in binary variable.
if you dont think you can handle binary and need a library to work with, refer to
How do I read JPEG and PNG pixels in C++ on Linux?
EDIT - or just use any image processing libraries such as http://cimg.eu since the objective appears to be interpretation of dice from an image.

converting color image to gray scale image

I am facing a problem with writing and reading a gray scale image in open cv using c++. This is my code to read a color image as gray scale image and to write it in a file:
cv::Mat source = cv::imread("c:\\users\\selva\\desktop\\newimage.jpg",CV_LOAD_IMAGE_GRAYSCALE);
cv::imwrite("c:\\users\\selva\\desktop\\grayscal.jpg",source);
Then i tried to read that image in a new project,
cv::Mat gray = cv::imread("c:\\users\\selva\\desktop\\grayscal.jpg",CV_LOAD_IMAGE_UNCHANGED);
But when i execute this code,
std::cout<<gray.channels(); The output in console is 3.
I am using opencv 2.4.7, i tried with .png format, but that does not help.
console value for std::cout<<source.channels(); is 1.
If my newimage.jpg is a gray scale image and i am reading as,
cv::Mat source = cv::imread("c:\\users\\selva\\desktop\\newimage.jpg",0);
the problem is same.
I am sure that i am loading correct image.
Please anyone answer why it happens. Thanks in advance.

sepFilter2D Opencv unexpected results

I'm trying to apply 8X8 separable mean filter on top of an image
The filter is 2D separable.
I'm converting the following code from Matlab,
Kernel = ones(n);
% for conv 2 without zeropadding
LimgLarge = padarray(Limg,[n n],'circular');
LimgKer = conv2(LimgLarge,Kernel,'same')/(n^2);
LKerCorr = LimgKer(n+1:end-n,n+1:end-n);
1st I pad the image with the filter size, than correlate 2d, and finally crop the image region.
Now, I'm trying to implement the same thing in C++ using opencv
I have loaded the image, than called the following commands:
m_kernelSize = 8;
m_kernelX = Mat::ones(m_kernelSize,1,CV_32FC1);
m_kernelX = m_kernelX / m_kernelSize;
m_kernelY = Mat::ones(1,m_kernelSize,CV_32FC1);
m_kernelY = m_kernelY / m_kernelSize;
sepFilter2D(m_logImage,m_filteredImage,m_logImage.depth(),m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);
I expected to receive the same results, but I'm still getting totally different results from Matlab.
I'd rather not to pad the image , do the correlation and finally crop the image again, I expected the same results using BORDER_REPLICATE argument.
Incidentally, I'm aware of copyMakeBorder function, but rather not use it, because sepFilter2D handles the regions by itself.
Since you said you are only loading the image before the code snippet you showed, I can see two potential flaws.
First, if you do nothing between the loading of the source image and your code snippet, then your source image would be an 8-bit image and, since you set the function argument ddepth to m_logImage.depth(), you are also requesting a 8-bit destination image.
However, after reading the documentation of sepFilter2D, I am not sure that this is a valid combination of src.depth() and ddepth.
Can you try using the following line:
sepFilter2D(m_logImage,m_filteredImage,CV_32F,m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);
Second, check that you loaded your source image using the flag CV_LOAD_IMAGE_GRAYSCALE, so that it only has one channel and not three.
I followed Matlab line by line, The mistake was somewhere else.
Anyways , The following two methods return the same results
Using a 8X8 filter
// Big filter mode - now used only for debug mode
m_kernel = Mat::ones(m_kernelSize,m_kernelSize,type);
cv::Mat LimgLarge(m_logImage.rows + m_kernelSize*2, m_logImage.cols + m_kernelSize*2,m_logImage.depth());
cv::copyMakeBorder(m_logImage, LimgLarge, m_kernelSize, m_kernelSize,
m_kernelSize, m_kernelSize, BORDER_REPLICATE);
// Big filter
filter2D(LimgLarge,m_filteredImage,LimgLarge.depth(),m_kernel,Point(-1,-1),0,BORDER_CONSTANT );
m_filteredImage = m_filteredImage / (m_kernelSize*m_kernelSize);
cv::Rect roi(cv::Point(0+m_kernelSize,0+m_kernelSize),cv::Point(m_filteredImage.cols-m_kernelSize, m_filteredImage.rows-m_kernelSize));
cv::Mat croppedImage = m_filteredImage(roi);
m_diffImage = m_logImage - croppedImage;
Second method, using separable 8x8 filter
sepFilter2D(m_logImage,m_filteredImage,m_logImage.depth(),m_kernelX,m_kernelY,Point(-1,-1),0,BORDER_REPLICATE);
m_filteredImage = m_filteredImage / (m_kernelSize*m_kernelSize);

Inconsistent outcome of findChessboardCorners() in opencv

I am writing C++ code with OpenCV where I'm trying to detect a chessboard on an image (loaded from a .jpg file) to warp the perspective of the image. When the chessboard is found by findChessboardCorners(), the rest of my code is working perfectly. But sometimes the function does not detect the pattern, and this behavior seems to be random.
For example, there is one image that works on it's original resolution 2560x1920, but not if I scale it down with GIMP first to 800x600. However, another image seems to do the opposite: doesn't work in original resolution, but does work scaled down.
Here's the bit of my code that does the detection:
Mat grayimg = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
if (img.data == NULL) {
printf("Unable to read image");
return 0;
}
bool patternfound = findChessboardCorners(grayimg, patternsize, corners,
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK);
if (!patternfound) {
printf("Chessboard not found");
return 0;
}
Is there some kind of bug in opencv causing this behavior? Does anyone has any tips on how to pre-process your image, so the function will work more consistently?
I already tried playing around with the parameters CALIB_CB_ADAPTIVE_THRESH, CALIB_CB_NORMALIZE_IMAGE, CALIB_CB_FILTER_QUADS and CALIB_CB_FAST_CHECK. I'm also having the same results when I pass in a color image.
Thanks in advance
EDIT: I'm using OpenCV version 2.4.1
I had a very hard time getting findChessboardCorners to work until I added a white boarder around the chessboard.
I found that as hint somewhere in the more recent documenation.
Before adding the border, it would sometimes be impossible to recognize the keyboard, but with the white border it works every time.
Welcome to the joys of real-world computer vision :-)
You don't post any images, and findChessboardCorners is a bit too high-level to debug. I suggest to display (in octave, or matlab, or with more OpenCV code) the location of the detected corners on top of the image, to see if enough are detected. If none, try to run cvCornerHarris by itself on the image.
Sometimes the cause of the problem is the excessive graininess of the image: try to blur is just a little and see if it helps.
Actually, try to remove the CALIB_CB_FAST_CHECK option, and give it a try.
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK is not the same as CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK, you should use | (binary or)