I am trying to detect the biggest/larger rectangular shape and draw bounding box to the detected area. I have tried different way to detect perfect edge ( Edges with no holes) for contour detection. I searched on stackoverflow and the solution proposed OpenCV sharpen the edges (edges with no holes) and Segmentation Edges did not work with my sample image.
I would like to detect biggest/larger rectangular shape on the following two images Original Image 1 and Original Image 2
Below is the code that i use to preprocess the image before calling findcontour.
public Mat processGrayScaleImage(Mat grayImage){
Mat value = new Mat();
Mat sobx = new Mat();
Mat soby = new Mat();
Mat grad_abs_val_approx = new Mat();
Imgproc.GaussianBlur(grayImage, value, new Size(9, 9), 2, 2);
Mat imf = new Mat();
value.convertTo(imf, CV_32FC1, 0.5f, 0.5f);
Imgproc.Sobel(imf, sobx, -1, 1, 0);
Imgproc.Sobel(imf, soby, -1, 0, 1);
sobx = sobx.mul(sobx);
soby = soby.mul(soby);
Mat sumxy = new Mat();
//Core.add(sobx,soby, sumxy);
Core.addWeighted(sobx, 0.5, soby, 0.5, 0, sumxy);
Core.pow(sumxy, 0.5, grad_abs_val_approx);
sobx.release();
soby.release();
sumxy.release();;
Mat filtered = new Mat();
Imgproc.GaussianBlur(grad_abs_val_approx, filtered, new Size(9, 9), 2, 2);
grad_abs_val_approx.release();
final MatOfDouble mean = new MatOfDouble();
final MatOfDouble stdev = new MatOfDouble();
Core.meanStdDev(filtered, mean, stdev);
Mat thresholded = new Mat();
Imgproc.threshold(filtered, thresholded, mean.toArray()[0], 1.0, Imgproc.THRESH_TOZERO);
Mat converted = new Mat();
thresholded.convertTo(converted, CV_8UC1);
thresholded.release();
filtered.release();
return converted;
}
I have also tried the saturation Channel in HSV color space in place of gray image but it does not work.
Does anybody have an idea why it does not works with the code posted above ?
How can I process image in order to sharpen the edges for contour detection ?
Any relevant information(either in Java or C++ or Python ) is welcomed.
//UPDATE : 05/04/2017
I have tested difference of gaussian on the first original image. The result is not useful for contour detection. The resulting image xhttps://i.stack.imgur.com/ONw9F.jpg The code i used :
public static Mat dog(Mat grayImage){
Mat blur1 = new Mat();
Mat blur2 = new Mat();
Mat dog = new Mat();
int radius1 = 15;
int radius2 = radius1 + 6;
Imgproc.GaussianBlur(grayImage, blur1, new Size(radius1, radius1), 5);
Imgproc.GaussianBlur(grayImage, blur2, new Size(radius2, radius2), 5);
Core.absdiff(blur1, blur2, dog);
Core.multiply(dog, new Scalar(100), dog);
Imgproc.threshold(dog, dog, 55, 255, Imgproc.THRESH_BINARY_INV);
return dog;
}
I have also tried to apply CLAHE before difference of gaussian and here is the result [Image result of difference of gaussian and clahe] xhttps://i.stack.imgur.com/DDbqg.jpg
Update #2
I have tried the houghline as suggested below but it does not work. here is my code applied to grayscale image
public static void houghLines(Mat greyImg, Context ctx){
Mat lines = new Mat();
Mat binary = new Mat();
Mat original = greyImg.clone();
int threshold = 35;
int minLineSize = 20;
int lineGap = 30;
Imgproc.Canny(greyImg, greyImg, 20, 30, 3, false);
Imgproc.HoughLinesP(greyImg, lines, 1, Math.PI/70, threshold, minLineSize, lineGap);
for (int x = 0; x < lines.rows(); x++)
{
double[] vec = lines.get(x, 0);
double x1 = vec[0],
y1 = vec[1],
x2 = vec[2],
y2 = vec[3];
Point start = new Point(x1, y1);
Point end = new Point(x2, y2);
double dx = x1 - x2;
double dy = y1 - y2;
double dist = Math.sqrt (dx*dx + dy*dy);
if(dist>300.d)
Imgproc.line(original, start, end, new Scalar(0,255, 0, 255),5);
}
}
The result image after i applied canny xhttps://i.stack.imgur.com/VtGNl.jpg and the final result xhttps://i.stack.imgur.com/KIUan.jpg
Update #3 : 06/04/2017
I tried Houghlines and not HoughlinesP. It does not work. Below is the code
public static void houghLines(Mat Original, Context ctx){
Mat lines = new Mat();
Mat binary = new Mat();
Mat greyImg = new Mat();
Mat im = Original.clone();
Imgproc.cvtColor(im, greyImg, Imgproc.COLOR_RGB2GRAY);
Imgproc.Canny(greyImg, binary, 20, 30, 3, true);
Imgproc.HoughLines(binary, lines, 1, Math.PI/70, 35);
for (int i = 0; i < lines.cols(); i++){
double data[] = lines.get(0, i);
double rho = data[0];
double theta = data[1];
double cosTheta = Math.cos(theta);
double sinTheta = Math.sin(theta);
double x0 = cosTheta * rho;
double y0 = sinTheta * rho;
Point pt1 = new Point(x0 + 10000 * (-sinTheta), y0 + 10000 * cosTheta);
Point pt2 = new Point(x0 - 10000 * (-sinTheta), y0 - 10000 * cosTheta);
Imgproc.line(im, pt1, pt2, new Scalar(0, 0, 200), 3);
}
}
The resulting canny image for the code above : _https://i.stack.imgur.com/6k8sF.jpg The resulting image with lines _https://i.stack.imgur.com/3e9CB.jpg
At this time of writing, i have not found a working solution. Does anybody have an idea for a working solution ?
I tried a quick check on the image you shared. And I got this result after I tweaked parameters of canny and hough lines a little. Not sure what kind of generalisation you need, but give it a try.
Here is my code:
import cv2 as cv2
import numpy as np
# fn = '2PeyG.jpg'
fn = 'qEFMj.jpg'
r_scale = 0.1
# OpenCV reads image with BGR format
img = cv2.imread(fn)
img = cv2.resize(img, (0, 0), fx=r_scale, fy=r_scale)
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img, 20, 30, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/70, 35)
for rho, theta in lines[0]:
if (np.pi/70 <= theta <= np.pi/7) or (2.056 < theta < 4.970) or (1.570 <= theta <= 1.600):
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),1)
cv2.imshow('edges', edges)
cv2.imshow('overlay', img)
# cv2.imwrite('lines_overlay.png', img)
cv2.waitKey(3000)
The result I got was
I agree this is not what you are looking exactly, but probably a good starting point. Hope this helps :)
来源:https://stackoverflow.com/questions/43209866/sharpen-the-edges