drawContours around detected document using opencv for android gives strange bug - android

I am new to OpenCv4Android. I am trying to auto detect document using OpenCv4Android sdk. Initially i have gone through issue of landscape opencv camera . Somehow i managed to change the orientation of opencv JavaCameraview to portrait. I made following changes in default classes of opencv sdk to orient opencv camera in portrait :
1) In CameraBridgeViewBase class
Matrix matrix = new Matrix();
matrix.setRotate(90f);
Bitmap bitmap = Bitmap.createBitmap(mCacheBitmap, 0, 0, mCacheBitmap.getWidth(), mCacheBitmap.getHeight(), matrix, true);
2) now in drawbitmap method replace above bitmap with mCacheBitmap
3) now , In JavaCameraView class
if ((getLayoutParams().width == ActionBar.LayoutParams.MATCH_PARENT) && (getLayoutParams().height == ActionBar.LayoutParams.MATCH_PARENT))
mScale = Math.min(((float)height)/mFrameWidth, ((float)width)/mFrameHeight);
else
mScale = 0;
After above changes , i am able to orient camera in portrait mode . But , having strange issue in detecting document . See below images
As you can see in first image , before customization i can detect paper in full green color . And in 2nd image you can see the bug of drawing line (drawContours) around paper
what i follow to detect paper is : GaussianBlur -> Canny edge detection -> findContours -> drawContour
In OnCameraFrame method :
mRgba = inputFrame.rgba();
Mat mGray = new Mat();
Mat edged = new Mat();
Imgproc.cvtColor(mRgba,mGray,Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(mRgba,mGray,new Size(5,5),0);
-> and then finding contours
Imgproc.findContours(edged, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
-> Then i found the largest contour and finally the drawContours on that
Imgproc.drawContours(mRgba, contours, maxI, new Scalar(0, 255, 0), 5);
I don't know where i m wrong..! Please help me to solve this strange issue.
#Rick M. following is the original image :
#ilke444 , following is the image after edge detection which is perfectly what i want :

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.

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.

Converting RGB2HSV in OPENCV4Android

I have started working on OpenCv4Android recently.I was able to successfully run Image Manipulations Sample given.I wanted to covert RGB image to HSV as a test exercise.I have done OpenCv on C++(WINDOWS) and know basic functions too.
So the cvtcolor fucntions take the following arguments:
cvtcolor(mat src,mat dst,Imgproc.COLOR_TRANSFORMATION_TYPE,Number of Channels);
I tried different methods to check the output but I get only the cameraPreview that is the LIVE CAMERA view.Note:Other Functions like Canny Still work(shows OUTPUT).
Also I have doubt that is it neccessary to use JNI i.e NDK for this purpose or can most of the applications using OPENCV Library can me done(written) in main_activity.java and compiled??
I am starter to OpenCv4Android.Sorry If I have been over-descriptive and all suggestions are welcome. Thank You.
//METHOD 1
case ImageManipulationsActivity.VIEW_MODE_HSV:
rgba=inputFrame.rgba();
rgbaInnerWindow = rgba.submat(top, top + height, left, left + width);
Imgproc.cvtColor(rgba, mIntermediateMat, Imgproc.COLOR_RGB2HSV_FULL);
Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_HSV2RGB_FULL);
rgbaInnerWindow.release();
break;
//METHOD 2
case ImageManipulationsActivity.VIEW_MODE_HSV:
Mat hsv= null;
// rgba=inputFrame.rgba();
// rgbaInnerWindow = rgba.submat(top, top + height, left, left + width);
Imgproc.cvtColor(rgbaInnerWindow, mIntermediateMat, Imgproc.COLOR_RGBA2RGB);
Imgproc.cvtColor(mIntermediateMat, hsv, Imgproc.COLOR_RGB2HSV_FULL);
Imgproc.cvtColor(hsv, rgbaInnerWindow, Imgproc.COLOR_HSV2RGB_FULL);
rgbaInnerWindow.release();
break;
//METHOD 3
case ImageManipulationsActivity.VIEW_MODE_HSV:
rgbaInnerWindow = rgba.submat(top, top + height, left, left + width);
Imgproc.cvtColor(rgbaInnerWindow, rgbaInnerWindow, Imgproc.COLOR_HSV2RGB_FULL);
rgbaInnerWindow.release();
break;
If you want to display HSV format image, try this code (I havn't tested it, but it should work.)
Mat mRgba = inputFrame.rgba();
// mBgr is Mat in BGR Format
Imgproc.cvtColor(rgba, mBgr, Imgproc.COLOR_RGBA2BGR, 3);
// mHsv is Mat in Hsv Format
Imgproc.cvtColor(mBgr, mHsv, Imgproc.COLOR_BGR2HSV, 3);
// To display the image, we assume that mHsv is in BGR
Imgproc.cvtColor(mHsv, mRgb, Imgproc.COLOR_BGR2RGBA, 4);
// Display the image
Also I have doubt that is it neccessary to use JNI i.e NDK for this
purpose or can most of the applications using OPENCV Library can me
done(written) in main_activity.java and compiled??
No, you do not need to write native code for this, for most applications OpenCV Java bindings are sufficient. Even if you need to do it's pretty easy to do.

Weird issue with OpenCV drawContours on android

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.

Cropping image in Android using opencv

I am using OpenCV 2.3.1 in Android. I need to crop the image into half.
What I am doing is:
Mat mIntermediateMat2 = new Mat(frame_height,frame_width,rgba.type);
mIntermediateMat2 = rgba.clone();
mIntermediateMat2 = mIntermediateMat2.rowRange(0,frame_height/2);
Will the third step do the job or I have to add something more?
I saw Mat::operator() in opencv 2.3 documentation but unfortunately not able to find in the opencv Android package.
There are a few constructors for the Mat class, one of which takes a Mat and an ROI (region of interest).
Here's how to do it in Android/Java:
Mat uncropped = getUncroppedImage();
Rect roi = new Rect(x, y, width, height);
Mat cropped = new Mat(uncropped, roi);
I have always done cropping this way:
Mat image = ...; // fill it however you want to
Mat crop(image, Rect(0, 0, image.cols, image.rows / 2)); // NOTE: this will only give you a reference to the ROI of the original data
// if you want a copy of the crop do this:
Mat output = crop.clone();
Hope that helps!
Seems cv::getRectSubPix does what you want. Plus you don't have to allocate more space than you need. Also it does necessary interpolations if the cropped area is not aligned over an exact pixel.
This should do what you want. Input type will be the output type.
Mat dst;
getRectSubPix(src, Size(src.rows()/2,src.cols()), Point2f(src.rows()/4, src.cols()/2), dst);

Categories

Resources