I am working on an app where i need to identify text from an image and what could be the better way than using Tesseract. As Tesseract is an open source and widely accepted. I have used Tesseract in my app. So, i am getting images from user and then applying 2-3 operations on image to improve chances of getting result but i am not getting expected result.
Java Code ->
final Bitmap tessBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(tessBitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawBitmap(image, 0, 0, paint);
Mat tessMat = new Mat();
Utils.bitmapToMat(tessBitmap, tessMat);
Imgproc.cvtColor(tessMat, tessMat, Imgproc.COLOR_RGB2GRAY);
Imgproc.threshold(tessMat, tessMat, 0, 255, Imgproc.THRESH_BINARY + Imgproc.THRESH_OTSU);
final Bitmap newTessBitmap = Bitmap.createBitmap(tessMat.width(), tessMat.height(), Bitmap.Config.RGB_565);
Utils.matToBitmap(tessMat, newTessBitmap);
final Bitmap finalTessBitmap = Bitmap.createBitmap(newTessBitmap.getWidth(), newTessBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tessCanvas = new Canvas(finalTessBitmap);
Paint tessPaint = new Paint();
tessPaint.setColor(Color.BLACK);
tessCanvas.drawBitmap(newTessBitmap, 0, 0, tessPaint);
and then passing this bitmap to tesseract to get output but not getting efficient and sometimes i dont even get anything in output. I have compared my result with one online website https://www.newocr.com/ .
Which is also using tesseract in back end as it is claiming. i have also tried to contact them via email but coudlnt get anything from them.
mTess = new TessBaseAPI();
tessModelPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/tesseract/";
mTess.init(tessModelPath, "eng", TessBaseAPI.OEM_TESSERACT_ONLY); mTess.setPageSegMode(TessBaseAPI.PageSegMode.PSM_AUTO);
mTess.setImage(finalTessBitmap);
This is the base Tesseract code. Please help me solve my issue. Thanks...
Given below is the image i get after applying above mentioned operation but when i pass it to tesseract i did not get anything but when passing to newocr.com website it is producing exact text.
Result from newOcr.
This image is for results.
Please suggest me about what to do if you have any idea.
After Digging more and running the same image in python code i have found out that in python pytesseract it works like charm and producing exact output as newocr. But when i run in android it doesnt work that well. so may be the issue is with API of Tesseract. So, now if you know anything still which i can do to improve accuracy. Help me. Thanks in Advance.
$ tesseract 8UIBw.jpg -
Warning: Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 613
Tillamook
It was without any preprocessing...
$ tesseract -v
tesseract 4.0.0-253-g3948
leptonica-1.76.0 (Dec 14 2018, 15:34:47) [MSC v.1916 LIB Release x64]
libgif 5.1.4 : libjpeg 9b : libpng 1.6.35 : libtiff 4.0.9 : zlib 1.2.11 : libwebp 0.6.1 : libopenjp2 2.3.0
Found AVX
Found SSE
Related
I'm developing an Android app which uses a background Service to programmatically capture a screenshot of whatever is on the screen currently. I obtain the screenshot as a Bitmap.
Next, I successfully imported OpenCV into my Android project.
What I need to do now is blur a subset of this image, i.e. not the entire image itself, but a [rectangular] area or sub-region within the image. I have an array of Rect objects representing the rectangular regions that I need to blur within the screenshot.
I've been looking around for a tutorial on doing this with OpenCV in Java, and I haven't found a clear answer. The Mat and Imgproc classes are obviously the ones of interest, and there's the Mat.submat() method, but I've been unable to find a clear, straightforward tutorial on getting this done.
I've googled a lot, and none of the examples I've found are complete. I need to do this in Java, within the Android runtime.
What I need is: Bitmap >>> Mat >>> Imgproc>>> Rect >>> Bitmap with ROI
blurred.
Any experienced OpenCV devs out here, can you point me in the right direction? This is the only thing I'm stuck at.
Related:
Gaussian blurring with OpenCV: only blurring a subregion of an image?.
How to blur a rectagle with OpenCv.
How to blur some portion of Image in Android?.
The C++ code to achieve this task is shared below with comments and sample images:
// load an input image
Mat img = imread("C:\\elon_tusk.png");
img:
// extract subimage
Rect roi(113, 87, 100, 50);
Mat subimg = img(roi);
subimg:
// blur the subimage
Mat blurred_subimage;
GaussianBlur(subimg, blurred_subimage, Size(0, 0), 5, 5);
blurred_subimage:
// copy the blurred subimage back to the original image
blurred_subimage.copyTo(img(roi));
img:
Android equivalent:
Mat img = Imgcodecs.imread("elon_tusk.png");
Rect roi = new Rect(113, 87, 100, 50);
Mat subimage = img.submat(roi).clone();
Imgproc.GaussianBlur(subimg, subimg, new Size(0,0), 5, 5);
subimg.copyTo(img.submat(roi));
You could just implement your own helper function, let's call it roi (region of interest).
Since images in opencv are numpy ndarrays, you can do something like this:
def roi(image: np.ndarray, region: QRect) -> np.ndarray:
a1 = region.upperLeft().x()
b1 = region.bottomRight().y()
a2 = region.upperLeft().x()
b2 = region.bottomRight().y()
return image[a1:a2, b1:b2]
And just use this helper function to extract the subregions of the image that you are interested, blur them and put the result back on the original picture.
I am using Tess-Two for creating an OCR for Android. I used the same image for conversion, but the result is very different from the tesseract for desktop.
The desktop version of tesseract gives a better result.
I am using the following lines on Android:
val baseApi = TessBaseAPI()
baseApi.init(dirPath, "eng")
baseApi.setImage(mustOpen)
val recognizedText = baseApi.utF8Text
And on desktop, I am using just this simple command
tesseract image.png result
The sample image is:
this
The output for the image using tesseract for Desktop is:
VEGETABLE OF, RIVET een Sra) SUGAR, EDIBLE
VEGETABLE OIL, INVERT SUGAR S' SUGAR, CITRIC
RAISING 503 (ii), BAKING }, SALT,
SOLIDS (0.6 % [ DL-ACETYL TARTARIC
ACID ESTERS OF ‘AND
And, the output using tess-two for android is this:
'm mm W7 ' ' iii-E:
mmmmfiwgmb Ian»: came
a” ( om | mmmfiéu
mmormuguomws _
Won mm .. . . ml
mumm I'm‘n
( .
Which is very gibberish. Please help.
So as I commented on your post and just solved it for me, I thought I share.
The first problem for me was that the image needs to be preprocessed for better results. I'm using OpenCV for the preprocessing. Here https://android.jlelse.eu/a-beginners-guide-to-setting-up-opencv-android-library-on-android-studio-19794e220f3c is a good example how to set it up.
Then the image needs to be switched into a binary image. For me the following gives best results
Mat plateMat = Utils.loadResource(this,R.drawable.plate);
Mat gray = new Mat();
Imgproc.cvtColor(plateMat,gray,Imgproc.COLOR_BGR2GRAY);
Mat blur = new Mat();
Imgproc.GaussianBlur(gray,blur,new Size(3,3),0);
Mat thresh = new Mat();
Imgproc.adaptiveThreshold(blur,thresh,255, Imgproc.ADAPTIVE_THRESH_MEAN_C,Imgproc.THRESH_BINARY_INV,75,10);
Core.bitwise_not(thresh,thresh);
Bitmap bmp = Bitmap.createBitmap(thresh.width(),thresh.height(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(thresh,bmp);
Then I call Tesseract using the eng+osd language (in this order) you can find them here:
https://github.com/tesseract-ocr/tessdata
Then by using tesseract I do this:
TessBaseAPI tesseract = new TessBaseAPI();
tesseract.setDebug(true);
tesseract.init(getFilesDir().getAbsolutePath(),"eng+osd");
tesseract.setImage(bmp);
String utf8 = tesseract.getUTF8Text();
NOW THE REAL DEAL
The real problem why I got a different result in the end is simply because the tesseract version installed with Homebrew on my Mac was 4.1.0 meanwhile the official Tess-two repo still uses 3.05
By digging through the repos issues I found that the developer of Tess two has a new version with Tesseract 4 but it needed to be in a different repo. It is here
https://github.com/adaptech-cz/Tesseract4Android
Once I cloned it and used the extracted aar from the project, the results were the same and I can finally sleep in peace!
Not sure if this is the right way to ask, but please help. I have an image of a dented car. I have to process it and highlight the dents and return the number of dents. I was able to do it reasonably well with the following result:
The matlab code is:
img2=rgb2gray(i1);
imshow(img2);
img3=imtophat(img2,strel('disk',15));
img4=imadjust(img3);
layer=img4(:,:,1);
img5=layer>100 & layer<250;
img6=imfill(img5,'holes');
img7=bwareaopen(img6,5);
[L,ans]=bwlabeln(img7);
imshow(img7);
I=imread(i1);
Ians=CarDentIdentification(I);
However, when I try to do this using opencv, I get this:
With the following code:
Imgproc.cvtColor(source, middle, Imgproc.COLOR_RGB2GRAY);
Imgproc.equalizeHist(middle, middle);
Imgproc.threshold(middle, middle, 150, 255, Imgproc.THRESH_OTSU);
Please tell me how can I obtain better results in opencv, and also how to count the dents? I tried findcontour() but it gives a very large number. I tried on other images as well, but I'm not getting proper results.
Please help.
So you basically from the MATLAB site, imtophat does - Top-hat filtering computes the morphological opening of the image (using imopen) and then subtracts the result from the original image.
You could do this in OpenCV with the following steps:
Step 1: Get the disk structuring element
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15, 15))
Step 2: Compute opening of the image and then subtract the result from the original image
tophat = cv2.morphologyEx(v, cv2.MORPH_TOPHAT, kernel)
This gives following result -
Step 3 - Now you could just manually threshold it or use Otsu -
ret, thresh = cv2.threshold(tophat, 17, 255, 0)
which gives you the following image -
Since the OP wants the code in Java, here is the probable code in Java:
private Mat topHat(Mat image)
{
Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(15, 15), new Point (0, 0));
Mat dst = new Mat;
Imgproc.morphologyEx(image, dst, Imgproc.MORPH_TOPHAT, element, new Point(0, 0));
return dst;
}
Make sure you do this on a gray scale image (CvType.8UC1) and then you can threshold suitably.
i'm currently developing an android application to recognize digital numbers of an electricity meter. i've done most of the work but i still not getting a good result. 80% of the time i get a false one.
This is an example (i'm testing with a kitchen scale which is very similar to the meter) :
Original photo :
image after cropping and processing with OpenCV :
image after OCR (expected result that was obtained after several shots) :
image after OCR (unexpected result which is obtained often) :
Method used to process the image with OpenCV :
public Bitmap Bildverarbeitung (Bitmap image){
Mat tmp = new Mat (image.getWidth(), image.getHeight(), CvType.CV_8UC1);
Utils.bitmapToMat(image, tmp);
Imgproc.cvtColor(tmp, tmp, Imgproc.COLOR_RGB2GRAY);
Imgproc.GaussianBlur(tmp, tmp, new Size(3, 3), 0);
Imgproc.threshold(tmp, tmp, 0, 255, Imgproc.THRESH_OTSU);
Utils.matToBitmap(tmp, image);
return image;
}
I used two trained data but only one works better :
traineddata that works good
traineddata that doesn't work
can anyone help me get better results.. Is there any changes that i can do? or other methods that i can apply ? thanks in advance
I stumbled upon a weird problem with OpenCV drawContours on android.
Sometimes, (without apparent pattern) function drawContours produces this:
drawContours http://img17.imageshack.us/img17/9031/screenshotgps.png
while it should obviously produce just the white part.
To put it in context:
I detect edges using canny algorithm and then I find contours with
Imgproc.findContours(dil, contours, dummy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Then i select several contours that fit some requirements and I add them to a list:
List<MatOfPoint> goodContours = new ArrayList<MatOfPoint>();
After that I randomly select one contour and I draw it (filled with white) on mat and convert it to android Bitmap:
Mat oneContour = new Mat(orig.rows(), orig.cols(), CvType.CV_8UC1);
int index = (int) (Math.random() * goodContours.size());
Imgproc.drawContours(oneContour, goodContours, index, new Scalar(255, 255, 255), -1);
Bitmap oneContourBitmap = Bitmap.createBitmap(oneContour.cols(), oneContour.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(oneContour, oneContourBitmap);
Most of the times I get what I expect: white patch on a pure black background, but sometimes I get the above. I'm totally at a loss here. I suspect there could be some memory leakage but I try hard to release all Mat's immediately after they are of no use anymore (I also tried to release them at the end of a function where it all happens but without effect) but I'm unable to pinpoint the source of the problem.
Has anyone had similar issues?
I first discovered this on OpenCV 2.4.0 but it stays the same on 2.4.3.
Any suggestion is appreciated.