I want to crop a circle shape in an image.
I have an input image that is gray scale.
In this image have a circle shape. I need it.
How to do it using Open CV on Android?
Input image:
Bitmap bmpProces = BitmapFactory.decodeFile(path+inpuImage);
Mat imageMat = new Mat ( bmpProces.getHeight(), bmpProces.getWidth(), CvType.CV_8U);
Bitmap myBitmap32 = bmpProces.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, imageMat);
You have to create a mask,fill a circle in it according coordinates of target and use CopyTo to extract target circular area in your mask.Then you can crop a normal bounding rectangle of circle in mask Mat.You can see sample code and some more details here.There is a snippet code that you can convert it to java and use it:
// center and radius are the results of HoughCircle
// mask is a CV_8UC1 image with 0
cv::Mat mask = cv::Mat::zeros( img.rows, img.cols, CV_8UC1 );
circle( mask, center, radius, Scalar(255,255,255), -1, 8, 0 ); //-1 means filled
img.copyTo( dst, mask ); // copy values of img to dst if mask is > 0.
Related
I am using following code to detect edges from given document.
private Mat edgeDetection(Mat src) {
Mat edges = new Mat();
Imgproc.cvtColor(src, edges, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(edges, edges, new Size(5, 5), 0);
Imgproc.Canny(edges, edges, 10, 30);
return edges;
}
And then I can find the document from this edges by finding largest contour from this.
My problem is I can find the document from following pic:
but not from following pic:
How can I improve this edge detection?
I use Python, but the main idea is the same.
If you directly do cvtColor: bgr -> gray for img2, then you must fail. Because the gray becames difficulty to distinguish the regions:
Related answers:
How to detect colored patches in an image using OpenCV?
Edge detection on colored background using OpenCV
OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
In your image, the paper is white, while the background is colored. So, it's better to detect the paper is Saturation(饱和度) channel in HSV color space. For HSV, refer to https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation.
Main steps:
Read into BGR
Convert the image from bgr to hsv space
Threshold the S channel
Then find the max external contour(or do Canny, or HoughLines as you like, I choose findContours), approx to get the corners.
This is the first result:
This is the second result:
The Python code(Python 3.5 + OpenCV 3.3):
#!/usr/bin/python3
# 2017.12.20 10:47:28 CST
# 2017.12.20 11:29:30 CST
import cv2
import numpy as np
##(1) read into bgr-space
img = cv2.imread("test2.jpg")
##(2) convert to hsv-space, then split the channels
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
##(3) threshold the S channel using adaptive method(`THRESH_OTSU`) or fixed thresh
th, threshed = cv2.threshold(s, 50, 255, cv2.THRESH_BINARY_INV)
##(4) find all the external contours on the threshed S
cnts = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
canvas = img.copy()
#cv2.drawContours(canvas, cnts, -1, (0,255,0), 1)
## sort and choose the largest contour
cnts = sorted(cnts, key = cv2.contourArea)
cnt = cnts[-1]
## approx the contour, so the get the corner points
arclen = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02* arclen, True)
cv2.drawContours(canvas, [cnt], -1, (255,0,0), 1, cv2.LINE_AA)
cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 1, cv2.LINE_AA)
## Ok, you can see the result as tag(6)
cv2.imwrite("detected.png", canvas)
In OpenCV there is function called dilate this will darker the lines. so try the code like below.
private Mat edgeDetection(Mat src) {
Mat edges = new Mat();
Imgproc.cvtColor(src, edges, Imgproc.COLOR_BGR2GRAY);
Imgproc.dilate(edges, edges, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10, 10)));
Imgproc.GaussianBlur(edges, edges, new Size(5, 5), 0);
Imgproc.Canny(edges, edges, 15, 15 * 3);
return edges;
}
I'm drawing a rectangle over a camera preview and i want to crop that specific region covered by the rectangle and display it in ImageView. I managed to crop the the Bitmap by using :
Bitmap croppedBmp = Bitmap.createBitmap(imageOriginal, 50, 100, 1000, 550);
Code to draw the rectangle :
Rect rect = new Rect(50, 100,1000, 550);
as you can see i'm using the same parameters but i'm not getting the desired result. What i'm missing here ?. Thank you in advance.
Camera Preview :
Cropped Bitmap displayed in new activity :
> Hi, I am using OpenCV android library grabcut() method to extract an image from background, but the problem is that the output bitmap contains background Same as original image and object become white .I need Object as its same as original image and background transparent
I am using this code
private static Bitmap makeBlackTransparent(Bitmap image) {
// convert image to matrix
Mat src = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Utils.bitmapToMat(image, src);
// init new matrices
Mat dst = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Mat tmp = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
Mat alpha = new Mat(image.getWidth(), image.getHeight(), CvType.CV_8UC4);
// convert image to grayscale
Imgproc.cvtColor(src, tmp, Imgproc.COLOR_BGR2GRAY);
// threshold the image to create alpha channel with complete transparency in black background region and zero transparency in foreground object region.
Imgproc.threshold(tmp, alpha, 100, 255, Imgproc.THRESH_BINARY);
// split the original image into three single channel.
List<Mat> rgb = new ArrayList<Mat>(3);
Core.split(src, rgb);
// Create the final result by merging three single channel and alpha(BGRA order)
List<Mat> rgba = new ArrayList<Mat>(4);
rgba.add(rgb.get(0));
rgba.add(rgb.get(1));
rgba.add(rgb.get(2));
rgba.add(alpha);
Core.merge(rgba, dst);
// convert matrix to output bitmap
Bitmap output = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, output);
return output;
}
There are 2 problems in your code:
Firstly you need to segment out the white background, so adjust your thresh to be near 220 - 240 and also use THRESH_BINARY_INV instead of THRESH_BINARY :
Imgproc.threshold(tmp, alpha, 230, 255, Imgproc.THRESH_BINARY_INV);
Secondly, you must pre-multiply the ARGB layers, as Android ImageView behaves weird without premultiplication, for that you need to use cvtColor with COLOR_RGBA2mRGBA flag:
// Create the final result by merging three single channel and alpha(BGRA order)
List<Mat> rgba = new ArrayList<Mat>(4);
rgba.add(rgb.get(0));
rgba.add(rgb.get(1));
rgba.add(rgb.get(2));
rgba.add(alpha);
Core.merge(rgba, dst);
Imgproc.cvtColor(dst, dst, Imgproc.COLOR_RGBA2mRGBA);
I am developing application in which I have to detect rectangular object and draw outline I am using Open cv android library....
I succesfully detect Circle and draw outline inside image but repeatedly fail to detect Square or rectangle and draw....Here is my code to for circle..
Bitmap imageBmp = BitmapFactory.decodeResource(MainActivityPDF.this.getResources(),R.drawable.loadingplashscreen);
Mat imgSource = new Mat(), imgCirclesOut = new Mat();
Utils.bitmapToMat(imageBmp , imgSource);
//grey opencv
Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur( imgSource, imgSource, new Size(9, 9), 2, 2 );
Imgproc.HoughCircles( imgSource, imgCirclesOut, Imgproc.CV_HOUGH_GRADIENT, 1, imgSource.rows()/8, 200, 100, 0, 0 );
float circle[] = new float[3];
for (int i = 0; i < imgCirclesOut.cols(); i++)
{
imgCirclesOut.get(0, i, circle);
org.opencv.core.Point center = new org.opencv.core.Point();
center.x = circle[0];
center.y = circle[1];
Core.circle(imgSource, center, (int) circle[2], new Scalar(255,0,0,255), 4);
}
Bitmap bmp = Bitmap.createBitmap(imageBmp.getWidth(), imageBmp.getHeight(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(imgSource, bmp);
ImageView frame = (ImageView) findViewById(R.id.imageView1);
//Bitmap bmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
frame.setImageBitmap(bmp);
any help for detect square/rectangle for android ......I am wondering from 2 days ..every example are in either C++ or in C++ and I can't get through that languages...
Thanks.
There are many ways of detecting a rectangle using opencv, the most appropriate way of doing this is by finding the contours after applying Canny Edge Detection.
Steps are as follows :-
1.Convert the image to MAT
Grayscale the image
3.Apply Gausian Blur
4.Apply Morphology for filling the holes if any
5.Apply Canny Detection
6.Find Contours of the image
7.Find the largest contour of the rest
8.Draw the largest contour.
Code is as follows -
1.Convert the image to MAT
Utils.bitmapToMat(image,src)
Grayscale the image
val gray = Mat(src.rows(), src.cols(), src.type())
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY)
3.Apply Gausian Blur
Imgproc.GaussianBlur(gray, gray, Size(5.0, 5.0), 0.0)
4.Apply Morphology for filling the holes if any and also dilate the image
val kernel = Imgproc.getStructuringElement(
Imgproc.MORPH_ELLIPSE, Size(
5.0,
5.0
)
)
Imgproc.morphologyEx(
gray,
gray,
Imgproc.MORPH_CLOSE,
kernel
) // fill holes
Imgproc.morphologyEx(
gray,
gray,
Imgproc.MORPH_OPEN,
kernel
) //remove noise
Imgproc.dilate(gray, gray, kernel)
5.Apply Canny Detection
val edges = Mat(src.rows(), src.cols(), src.type())
Imgproc.Canny(gray, edges, 75.0, 200.0)
6.Find Contours of the image
val contours = ArrayList<MatOfPoint>()
val hierarchy = Mat()
Imgproc.findContours(
edges, contours, hierarchy, Imgproc.RETR_LIST,
Imgproc.CHAIN_APPROX_SIMPLE
)
7.Find the largest contour of the rest
public int findLargestContour(ArrayList<MatOfPoint> contours) {
double maxVal = 0;
int maxValIdx = 0;
for (int contourIdx = 0; contourIdx < contours.size(); contourIdx++) {
double contourArea = Imgproc.contourArea(contours.get(contourIdx));
if (maxVal < contourArea) {
maxVal = contourArea;
maxValIdx = contourIdx;
}
}
return maxValIdx;
}
8.Draw the largest contour which is the rectangle
Imgproc.drawContours(src, contours, idx, Scalar(0.0, 255.0, 0.0), 3)
There you go you have found the rectangle .
If any error persist in getting the process .Try resizing the source Image to half of its height and width.
Have a look at the below link for proper Java code of the above explained
https://github.com/dhananjay-91/DetectRectangle
Also,
https://github.com/aashari/android-opencv-rectangle-detector
You are on the right way by using the Houghtransformation. Instead of using Houghcircles you have to use Houghlines and check the obtained lines for intersections. If you really have to find rectangles (and not 4 edged polygones) - you should look for lines with the same angle(+- a small offset) and if you found at least a pair of these lines you have to look for lines that lay perpendicular to this, find a pair as well and check for intersections. It should not be a big deal using vectors(endpoint - startpoint) and lines to perform the angle and intersection tests.
I'm doing a watershed segmentation and the marker image is derived from the source image put through a distance transform. The distance transform returns a floating point image (I have no idea about the bit-depth) and I have trouble putting it through the watershed method since it requires a 32 bit single channel image.
Can I use the mat's convertTo method to set the bit depth to 32?
I also have trouble trying to display the floating point image since the matToBitmap() method doesn't seem to accept them. (in Android)
Mat mImg = new Mat();
Mat mThresh = new Mat();
Mat mDist = new Mat();
ImageView imgView = (ImageView) findViewById(R.id.imageView);
Bitmap bmpIn = BitmapFactory.decodeResource(getResources(),
R.drawable.w1);
Utils.bitmapToMat(bmpIn, mImg);
Imgproc.cvtColor(mImg, mImg, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(mImg, mThresh, 0, 255, Imgproc.THRESH_BINARY
| Imgproc.THRESH_OTSU);
//Marker image for watershed
Imgproc.distanceTransform(mThresh, mDist, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_PRECISE);
//Conversions for watershed
Imgproc.cvtColor(mThresh, mThresh, Imgproc.COLOR_GRAY2BGR, 3);
//Floating-point image -> 32-bit single-channel
mDist.convertTo(...);
Imgproc.watershed(mThresh, mDist); //
Bitmap bmpOut = Bitmap.createBitmap(mThresh.cols(), mThresh.rows(),
Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mThresh, bmpOut);
imgView.setImageBitmap(bmpOut);
Yes, you can use the convertTo function to convert any opencv matrix to another type. The type to convert to should be set in a destination matrix with the same size. convertTo has optional parameters scale and shift, so you can avoid clipping and quantization errors when converting to fixed point depths. So for your code:
Mat mDist32 = Mat(mDist.rows,mDist.cols,CV_32SC1); // 32 bit signed 1 channel, use CV_32UC1 for unsigned
mDist.convertTo(mDist32,CV_32SC1,1,0);
Imgproc.watershed(mThresh,mDist32);