gpt4 book ai didi

java - 如何从 OpenCV Java 中的 HoughLines 变换中检测矩形

转载 作者:太空宇宙 更新时间:2023-11-03 22:03:54 26 4
gpt4 key购买 nike

我知道这是重复的帖子,但仍然无法实现。我遵循互联网上的一些指南,了解如何在 OpenCV 和 Java 中检测图像中的文档。我想出的第一个方法是在预处理一些图像处理(如模糊、边缘检测)之后使用 findContours,在获得所有轮廓之后我可以找到最大的轮廓并假设它是我正在寻找的矩形但它失败了在某些情况下,例如文件没有完全被拿走,就像缺少一个角一样。在尝试了几次和一些新的处理但根本不起作用之后,我发现 HoughLine 变换更容易。从现在开始,我拥有图像中的所有线条,但仍然不知道接下来要做什么来定义我想要的兴趣矩形。这是我到目前为止的实现代码:方法一:使用 findContours

Mat grayImage = new Mat();
Mat detectedEdges = new Mat();
// convert to grayscale
Imgproc.cvtColor(frame, grayImage, Imgproc.COLOR_BGR2GRAY);
// reduce noise with a 3x3 kernel
// Imgproc.blur(grayImage, detectedEdges, new Size(3, 3));
Imgproc.medianBlur(grayImage, detectedEdges, 9);
// Imgproc.equalizeHist(detectedEdges, detectedEdges);
// Imgproc.GaussianBlur(detectedEdges, detectedEdges, new Size(5, 5), 0, 0, Core.BORDER_DEFAULT);
Mat edges = new Mat();
// canny detector, with ratio of lower:upper threshold of 3:1
Imgproc.Canny(detectedEdges, edges, this.threshold.getValue(), this.threshold.getValue() * 3, 3, true);
// makes the object in white bigger
Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
Image imageToShow = Utils.mat2Image(edges);
updateImageView(cannyFrame, imageToShow);
/// Find contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(edges, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// loop over the contours
MatOfPoint2f approxCurve;
double maxArea = 0;
int maxId = -1;
for (MatOfPoint contour : contours) {
MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());
double area = Imgproc.contourArea(contour);
approxCurve = new MatOfPoint2f();
Imgproc.approxPolyDP(temp, approxCurve, Imgproc.arcLength(temp, true) * 0.02, true);
if (approxCurve.total() == 4 && area >= maxArea) {
double maxCosine = 0;
List<Point> curves = approxCurve.toList();
for (int j = 2; j < 5; j++) {
double cosine = Math.abs(angle(curves.get(j % 4), curves.get(j - 2), curves.get(j - 1)));
maxCosine = Math.max(maxCosine, cosine);
}
if (maxCosine < 0.3) {
maxArea = area;
maxId = contours.indexOf(contour);
}
}
}
MatOfPoint maxMatOfPoint = contours.get(maxId);
MatOfPoint2f maxMatOfPoint2f = new MatOfPoint2f(maxMatOfPoint.toArray());
RotatedRect rect = Imgproc.minAreaRect(maxMatOfPoint2f);
System.out.println("Rect angle: " + rect.angle);
Point points[] = new Point[4];
rect.points(points);
for (int i = 0; i < 4; ++i) {
Imgproc.line(frame, points[i], points[(i + 1) % 4], new Scalar(255, 255, 25), 3);
}

Mat dest = new Mat();
frame.copyTo(dest, frame);
return dest;

方法 2:使用 HoughLine 变换

// STEP 1: Edge detection
Mat grayImage = new Mat();
Mat detectedEdges = new Mat();
Vector<Point> start = new Vector<Point>();
Vector<Point> end = new Vector<Point>();
// convert to grayscale
Imgproc.cvtColor(frame, grayImage, Imgproc.COLOR_BGR2GRAY);
// reduce noise with a 3x3 kernel
// Imgproc.blur(grayImage, detectedEdges, new Size(3, 3));
Imgproc.medianBlur(grayImage, detectedEdges, 9);
// Imgproc.equalizeHist(detectedEdges, detectedEdges);
// Imgproc.GaussianBlur(detectedEdges, detectedEdges, new Size(5, 5), 0, 0, Core.BORDER_DEFAULT);
// AdaptiveThreshold -> classify as either black or white
// Imgproc.adaptiveThreshold(detectedEdges, detectedEdges, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 5, 2);
// Imgproc.Sobel(detectedEdges, detectedEdges, -1, 1, 0);
Mat edges = new Mat();
// canny detector, with ratio of lower:upper threshold of 3:1
Imgproc.Canny(detectedEdges, edges, this.threshold.getValue(), this.threshold.getValue() * 3, 3, true);
// apply gaussian blur to smoothen lines of dots
Imgproc.GaussianBlur(edges, edges, new org.opencv.core.Size(5, 5), 5);
// makes the object in white bigger
Imgproc.dilate(edges, edges, new Mat(), new Point(-1, -1), 1); // 1
Image imageToShow = Utils.mat2Image(edges);
updateImageView(cannyFrame, imageToShow);
// STEP 2: Line detection
// Do Hough line
Mat lines = new Mat();
int minLineSize = 50;
int lineGap = 10;
Imgproc.HoughLinesP(edges, lines, 1, Math.PI / 720, (int) this.threshold.getValue(), this.minLineSize.getValue(), lineGap);
System.out.println("MinLineSize: " + this.minLineSize.getValue());
System.out.println(lines.rows());
for (int i = 0; i < lines.rows(); i++) {
double[] val = lines.get(i, 0);
Point tmpStartP = new Point(val[0], val[1]);
Point tmpEndP = new Point(val[2], val[3]);
start.add(tmpStartP);
end.add(tmpEndP);
Imgproc.line(frame, tmpStartP, tmpEndP, new Scalar(255, 255, 0), 2);
}

Mat dest = new Mat();
frame.copyTo(dest, frame);
return dest;

HoughLine result 1 HoughLine result 2

如何从 HoughLine 结果中检测出需要的矩形?有人可以给我下一步来完成 HoughLine 变换方法。任何帮助都适用。我坚持了一段时间。

感谢您阅读本文。

最佳答案

这个答案几乎是我发布的其他两个答案(herehere)的混合体。但是我用于其他答案的管道可以针对您的情况进行一些改进。所以我认为值得发布一个新答案。

有很多方法可以实现您想要的。但是,我认为这里不需要使用 HoughLinesP 进行线检测。所以这是我在您的示例中使用的管道:

第 1 步:检测边缘

  • 调整如果输入图像太大(我注意到此管道在给定输入图像的缩小版本上效果更好)
  • 模糊灰度输入并使用Canny 过滤器检测边缘

第 2 步:找到卡片的角

  • 计算轮廓
  • 长度对轮廓进行排序,只保留最大
  • 生成此轮廓的凸包
  • 使用approxPolyDP简化凸包(这应该得到一个四边形)
  • 用近似多边形创建一个掩模
  • 返回四边形的4个点

第 3 步:单应性

  • 使用 findHomography 找到纸张的仿射变换(使用在第 2 步 找到的 4 个角点)
  • Warp 使用计算出的单应矩阵输入图像

注意:当然,一旦您在输入图像的缩小版本上找到纸张的角点,您就可以轻松计算出全尺寸输入图像上角点的位置.这是为了让翘曲的纸张获得最佳分辨率。

结果如下: enter image description here

vector<Point> getQuadrilateral(Mat & grayscale, Mat& output)
{
Mat approxPoly_mask(grayscale.rows, grayscale.cols, CV_8UC1);
approxPoly_mask = Scalar(0);

vector<vector<Point>> contours;
findContours(grayscale, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);

vector<int> indices(contours.size());
iota(indices.begin(), indices.end(), 0);

sort(indices.begin(), indices.end(), [&contours](int lhs, int rhs) {
return contours[lhs].size() > contours[rhs].size();
});

/// Find the convex hull object for each contour
vector<vector<Point> >hull(1);
convexHull(Mat(contours[indices[0]]), hull[0], false);

vector<vector<Point>> polygon(1);
approxPolyDP(hull[0], polygon[0], 20, true);
drawContours(approxPoly_mask, polygon, 0, Scalar(255));
imshow("approxPoly_mask", approxPoly_mask);

if (polygon[0].size() >= 4) // we found the 4 corners
{
return(polygon[0]);
}

return(vector<Point>());
}


int main(int argc, char** argv)
{

Mat input = imread("papersheet1.JPG");
resize(input, input, Size(), 0.1, 0.1);
Mat input_grey;
cvtColor(input, input_grey, CV_BGR2GRAY);
Mat threshold1;
Mat edges;
blur(input_grey, input_grey, Size(3, 3));
Canny(input_grey, edges, 30, 100);


vector<Point> card_corners = getQuadrilateral(edges, input);
Mat warpedCard(400, 300, CV_8UC3);
if (card_corners.size() == 4)
{
Mat homography = findHomography(card_corners, vector<Point>{Point(warpedCard.cols, warpedCard.rows), Point(0, warpedCard.rows), Point(0, 0), Point(warpedCard.cols, 0)});
warpPerspective(input, warpedCard, homography, Size(warpedCard.cols, warpedCard.rows));
}

imshow("warped card", warpedCard);
imshow("edges", edges);
imshow("input", input);
waitKey(0);

return 0;
}

这是 C++ 代码,但翻译成 Java 应该不难。

关于java - 如何从 OpenCV Java 中的 HoughLines 变换中检测矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44020751/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com