Digital numbers recognition with Opencv + OCR on android - android

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

Related

Blurring a Rect within a screenshot

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.

Not getting efficient result from Tesseract OCR as newocr producing

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

comparison of channel images in android and matlab

so i have a 1024x1024 greyscale image, when i open this picture using matlab, matlab detect that the image is 1024x1024 uint8.
the problem is when I do image processing with android, where I divide the image into several parts, then do the attacking process to some parts of the image, then re-combine the image. then I open the image of the attacking result using matlab, and matlab detect image size 1024x1024x3 uint8. I've tried to change the image using the cvtColor function provided by opencv to change the image channel but the image is still considered 3 channel by matlab. this is a sample image before and after done image processing with android (left:before attacking, right:after attacking)
this is one of the attacking functions named gaussian noised which I implement using android
private Bitmap GaussianNoise(Bitmap src, double variance) {
Bitmap hasil = src;
Mat input = new Mat();
Mat imGray = new Mat();
Utils.bitmapToMat(src, input);
Imgproc.cvtColor(input, imGray, Imgproc.COLOR_RGBA2GRAY);
Mat noise = new Mat(imGray.size(), CvType.CV_64F);
Mat resultMat = new Mat();
Core.normalize(imGray, resultMat, 0.0, 1.0, Core.NORM_MINMAX, CV_64F);
Core.randn(noise, 0, Math.sqrt(variance));
Core.add(resultMat, noise, resultMat);
Core.normalize(resultMat, resultMat, 0.0, 1.0, Core.NORM_MINMAX, CV_64F);
resultMat.convertTo(resultMat, imGray.type(), 255, 0);
Utils.matToBitmap(resultMat, hasil);
return hasil;
}
all forms of assistance will be greatly appreciated

Thresholding in Android using opencv

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.

Watershed example in [android] opencv

Currently trying
<code>
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
Imgproc.Canny(mRgba, markers, 80, 90);
Mat threeChannel = new Mat();
Imgproc.cvtColor(mRgba, threeChannel, Imgproc.COLOR_BGR2GRAY);
Imgproc.watershed(threeChannel, markers);
return threeChannel;
}
</code>
However, it fails with
CvException [org.opencv.core.CvException: /home/reports/ci/slave/50-SDK/opencv/modules/imgproc/src/segmentation.cpp:147: error: (-210) Only 8-bit, 3-channel input images are supported in function void cvWatershed(const CvArr*, CvArr*)
Could you advise how to appropriately use the markers from a Canny/Sobel edge detection to feed a Watershed algorithm? Android-specifics would be greatly helpful as this is my first Android project.
The error states that the input image for watershed() must be an 8-bit 3-channels image. After calling cvtColor(), print the number of channels of threeChannel. Don't be surprised if it outputs 1.
Pass mRgba directly to watershed() and see what happens. One of my previous answers have working code using watershed, you can use that for testing.
You need to just convert your image from 4 channel to 3 channels.
For example
Imgproc.cvtColor(mat , mat, Imgproc.COLOR_BGRA2BGR);

Categories

Resources