gpt4 book ai didi

java - OpenCV - 在视频和图像上查找黑板边缘

转载 作者:行者123 更新时间:2023-12-03 13:46:36 25 4
gpt4 key购买 nike

更新
你可以在这里找到我在我的 GitHub 上测试的所有图像:
GitHub repository with sources
还有 2 个视频,检测也应该在其中进行
原始问题
我尝试使用 OpenCV 4.x.x 找到黑板的边缘(如下图),但不知何故我无法成功。我目前的代码如下所示:(带有 OpenCV 和实时摄像头馈送的 Android),其中 imgMat 是来自摄像头馈送的 Mat:

    Mat gray = new Mat();
Imgproc.cvtColor(imgMat, gray, Imgproc.COLOR_RGB2BGR);

Mat blurred = new Mat();
Imgproc.blur(gray, blurred, new org.opencv.core.Size(3, 3));

Mat canny = new Mat();
Imgproc.Canny(blurred, canny, 80, 230);

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new org.opencv.core.Size(2, 2));
Mat dilated = new Mat();
Imgproc.morphologyEx(canny, dilated, Imgproc.MORPH_DILATE, kernel, new Point(0, 0), 10);
Mat rectImage = new Mat();
Imgproc.morphologyEx(dilated, rectImage, Imgproc.MORPH_CLOSE, kernel, new Point(0, 0), 5);
Mat endproduct = new Mat();
Imgproc.Canny(rectImage, endproduct, 120, 230);

List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(endproduct, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

double maxArea = 0;
boolean hasContour = false;
MatOfPoint2f biggestContour = new MatOfPoint2f();
Iterator<MatOfPoint> each = contours.iterator();
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
if (area > maxArea) {
maxArea = area;
biggestContour = new MatOfPoint2f(wrapper.toArray());
hasContour = true;
}
}

if (hasContour) {
Mat output = imgMat.clone();

MatOfPoint2f approx = new MatOfPoint2f();
MatOfPoint poly = new MatOfPoint();

Imgproc.approxPolyDP(biggestContour, approx, Imgproc.arcLength(biggestContour, true) * .02, true);
approx.convertTo(poly, CvType.CV_32S);

Rect rect = Imgproc.boundingRect(poly);

}
不知何故,我无法让它工作,尽管相同的代码(用 python 编写)在我的电脑上用视频工作。我从矩形中获取输出并将其显示在我的移动屏幕上,在那里它闪烁很多并且无法正常工作。
这些是我尝试使用 python 程序的图像,它们有效:
big blackboard
big blackboard2
我究竟做错了什么?我无法经常检测到黑板的边缘。
关于黑板的附加信息:
  • 总是矩形
  • 可能有不同的照明
  • 文本应该被忽略,只有主板应该被检测到
  • 外部黑板也应忽略
  • 只应显示/返回主板的轮廓

  • 感谢您的任何建议或代码!

    最佳答案

    我使用 HSV 是因为这是检测特定颜色的最简单方法。我使用丰度测试来自动选择颜色阈值(因此这适用于绿色或蓝色板)。但是,此测试在白色或黑色板上会失败,因为根据色调,白色和黑色算作所有颜色。相反,在 HSV 中,白色和黑色最容易被检测为非常低的饱和度(白色)或非常低的值(黑色)。
    我对每个进行了 3 向检查,并选择了其中像素最多的蒙版(我假设板是图像的大部分)。我不确定这将如何在其他图像上起作用,因为我们这里只有一个图像,所以这可能适用于其他电路板,也可能不适用于其他电路板。
    我使用 approxPolyDP 减少轮廓中的点数,直到我有 4 个点并用它来绘制形状。
    enter image description here
    enter image description here

    import cv2
    import numpy as np

    # get unique colors (to speed up search) and return the most abundant mask
    def getAbundantColor(channel, margin):
    # get uniques
    unique_colors, counts = np.unique(channel, return_counts=True);

    # check for the most abundant color
    most = None;
    biggest_count = -1;
    for col in unique_colors:
    # count number of white pixels
    mask = cv2.inRange(channel, int(col - margin), int(col + margin));
    count = np.count_nonzero(mask);

    # if bigger, set new "most"
    if count > biggest_count:
    biggest_count = count;
    most = mask;
    return most, biggest_count;

    # load image
    img = cv2.imread("blackboard.jpg");

    # it's huge, scale down so that we can see the whole thing
    h, w = img.shape[:2];
    scale = 0.25;
    h = int(scale*h);
    w = int(scale*w);
    img = cv2.resize(img, (w,h));

    # hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV);
    h,s,v = cv2.split(hsv);

    # median blur to get rid of most of the text
    h = cv2.medianBlur(h, 5);
    s = cv2.medianBlur(s, 5);
    v = cv2.medianBlur(v, 5);

    # get most abundant color
    color_margin = 30;
    hmask, hcount = getAbundantColor(h, color_margin);

    # detect white and black separately
    light_margin = 30;
    # white
    wmask = cv2.inRange(s, 0, light_margin);
    wcount = np.count_nonzero(wmask);

    # black
    bmask = cv2.inRange(v, 0, light_margin);
    bcount = np.count_nonzero(bmask);

    # check which is biggest
    sorter = [[hcount, hmask], [wcount, wmask], [bcount, bmask]];
    sorter.sort();
    mask = sorter[-1][1];

    # dilate and erode to close holes
    kernel = np.ones((3,3), np.uint8);
    mask = cv2.dilate(mask, kernel, iterations = 2);
    mask = cv2.erode(mask, kernel, iterations = 4);
    mask = cv2.dilate(mask, kernel, iterations = 2);

    # get contours # OpenCV 3.4, in OpenCV 2* or 4* it returns (contours, _)
    _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);

    # for each contour, approximate a simpler shape until we have 4 points
    simplified = [];
    for con in contours:
    # go until we have 4 points
    num_points = 999999;
    step_size = 0.01;
    percent = step_size;
    while num_points >= 4:
    # get number of points
    epsilon = percent * cv2.arcLength(con, True);
    approx = cv2.approxPolyDP(con, epsilon, True);
    num_points = len(approx);

    # increment
    percent += step_size;

    # step back and get the points
    # there could be more than 4 points if our step size misses it
    percent -= step_size * 2;
    epsilon = percent * cv2.arcLength(con, True);
    approx = cv2.approxPolyDP(con, epsilon, True);
    simplified.append(approx);
    cv2.drawContours(img, simplified, -1, (0,0,200), 2);

    # print out the number of points
    for points in simplified:
    print("Num Points: " + str(len(points)));

    # show image
    cv2.imshow("Image", img);
    cv2.imshow("Hue", h);
    cv2.imshow("Mask", mask);
    cv2.waitKey(0);
    编辑:为了适应电路板颜色和外观的不确定性,我假设电路板本身将占图片的大部分。涉及分拣机的线条正在寻找图像中最丰富的颜色。如果板后面的白墙在图像中占据了更多空间,那么这将是为蒙版选择的颜色。
    还有其他方法可以尝试只选择电路板,但很难想出一个包罗万象的解决方案。如果您能想出某种方式来屏蔽电路板,那么其余代码应该可以完成相同的工作。如果您愿意对未知的颜色假设做出让步并提供失败案例的原始图片,那么我可能会想出一个合适的面具。

    关于java - OpenCV - 在视频和图像上查找黑板边缘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66461085/

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