【问题标题】:get coordinates of 4 corners of display screen on image获取图像上显示屏4个角的坐标
【发布时间】:2019-12-26 01:27:58
【问题描述】:

我正在尝试获取图像上的 4 个屏幕角(显示)。我有两张从同一位置拍摄的图像(所以我认为好的起点是提取两张图像/第一张和第二张图像/之间的差异)。只是屏幕上的图像发生了变化。所以我想获得显示屏角的上/下左/右(X,Y)坐标。

我正在使用带有 cv2 和 numpy 的 python 2.7(如果可能,不要使用其他模块)。不幸的是,我不知道如何获得这些坐标。

有什么想法吗? 附:示例代码会很棒,非常感谢,非常感谢

最终结果:

【问题讨论】:

标签: python numpy opencv image-processing


【解决方案1】:

我创建了一个新的解决方案,利用图像之间的差异并从中找到轮廓。我在底部使用霍夫线处理留下了旧的解决方案。

import numpy as np
import cv2


def main():
    im1 = cv2.imread('s123/ss1.jpg')
    im2 = cv2.imread('s123/ss2.jpg')

    gray1 = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY)

    # Try to match the two image's exposures
    gray1 = cv2.equalizeHist(gray1)
    gray2 = cv2.equalizeHist(gray2)

    # Find the difference and threshold it
    diff = cv2.absdiff(gray1, gray2)
    _, thresh = cv2.threshold(diff, 50, 255, cv2.THRESH_BINARY)

    # Filtering to improve the thresholded image
    thresh = cv2.medianBlur(thresh, 5)
    thresh = cv2.dilate(thresh, None, iterations=2)

    # Calculate contours and find the largest one
    _, cnts, hierachy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnt = max([c for c in cnts], key=lambda x: cv2.contourArea(x))

    cv2.drawContours(im1, [cnt], 0, (0, 255, 0), 3)

    # Remove the concavities
    hull = cv2.convexHull(cnt)
    cv2.drawContours(im1, [hull], 0, (255, 0, 0), 2)
    hull = [tuple(p[0]) for p in hull]

    # Find all the corners
    tr = max(hull, key=lambda x: x[0] - x[1])
    cv2.circle(im1, tr, 3, (0, 0, 255), -1)

    tl = min(hull, key=lambda x: x[0] + x[1])
    cv2.circle(im1, tl, 3, (0, 0, 255), -1)

    br = max(hull, key=lambda x: x[0] + x[1])
    cv2.circle(im1, br, 3, (0, 0, 255), -1)

    bl = min(hull, key=lambda x: x[0] - x[1])
    cv2.circle(im1, bl, 3, (0, 0, 255), -1)

    cv2.imshow('im1', im1)
    cv2.imshow('diff', thresh)

    cv2.waitKey(0)


if __name__ == '__main__':
    main()

这种方法的缺点是需要在屏幕上有很大差异(即 1&2 有效,但 1&3 无效,但 2&3 有效,因为 2 大部分是白色的)。如果您想要更强大的方法,请尝试 background subtractor,这将需要更多图像。


我对这两个图像进行平均,然后使用霍夫线处理来找到这些线。然后我过滤了这些,然后找到了交叉点:

import numpy as np
import cv2


# Code to find line intersections. From https://stackoverflow.com/a/20677983
def line_intersection(line1, line2):
    xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])

    def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

    div = det(xdiff, ydiff)
    if div == 0:
        return -1, -1

    d = (det(*line1), det(*line2))
    x = det(d, xdiff) / div
    y = det(d, ydiff) / div
    return x, y


def main():
    im1 = cv2.imread('GaJrr.jpg')
    im2 = cv2.imread('kR2pl.jpg')

    gray1 = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(im2, cv2.COLOR_BGR2GRAY)

    # Average the images
    diff = cv2.addWeighted(gray1, 0.5, gray2, 0.5, 0)

    # Canny and Hough lines
    c = cv2.Canny(diff, 89, 200)
    lines = cv2.HoughLines(c, 1, np.pi / 180, 100, None, 0, 0)

    pts = []

    # Create segments for each line
    if lines is not None:
        for i in range(len(lines)):
            rho = lines[i][0][0]
            theta = lines[i][0][1]
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a * rho
            y0 = b * rho
            pt1 = np.array([int(x0 + 1000 * (-b)), int(y0 + 1000 * a)])
            pt2 = np.array([int(x0 - 1000 * (-b)), int(y0 - 1000 * a)])

            if not any([np.linalg.norm(pt1 - p[0]) < 100 for p in pts]):    # Filter out lines too close to each other
                pts.append(np.array([pt1, pt2]))

                cv2.line(im1, tuple(pt1), tuple(pt2), (0, 0, 255), 1, cv2.LINE_AA)

    for pt in pts:
        for comp in pts:
            intersect = np.array(line_intersection(pt, comp))
            if any(intersect < 0) or intersect[0] > im1.shape[1] or intersect[1] > im1.shape[0]:    # Filter out off-screen intersections
                continue

            intersect = np.asarray(intersect, dtype=int)
            print(intersect)
            cv2.circle(im1, tuple(intersect), 3, (0, 255, 0), -1)

    cv2.imshow('im1', im1)

    cv2.waitKey(0)


if __name__ == '__main__':
    main()

这绝对可以优化一堆。

【讨论】:

  • 谢谢。粘贴在问题作品中的 2 张图像的代码。但是我从房间的不同位置尝试了您的代码,但失败了。如果您想尝试,这里有测试文件。 wetransfer.com/downloads/…。房间内任何位置都有通用代码会更好。因为总是只有显示屏上的图像发生变化,没有别的。
  • @peter 我已更改答案以使用图像之间的差异。如果您有很多图片(或视频),您可能需要查看正确的background subtraction
【解决方案2】:

你应该看看特征检测部分的opencv python tutorial,有一些算法可能会提供一些帮助(背后的数学解释很好),但据我了解可能是Shi-Tomasi algorithm最适合您的情况,这里有一个例子:

def get_corners(img):
    img_m = np.float32(img)
    img_m = cv2.cvtColor(img_m,cv2.COLOR_BGR2GRAY)
    corners = cv2.goodFeaturesToTrack(img_m,4,0.01,15)
    corners = np.int0(corners)
    return corners

img = cv2.imread("...") #you should make sure that the image is colored or else it's going to give an error
img_g = get_corners(img)
for i in img_g:
    x,y = i.ravel()
    cv.circle(img,(x,y),3,255,-1)
cv2.imshow('img', img)
cv2.waitKey(0)

但您应该永远记住:计算机视觉是一个研究类型领域,这意味着您会尝试不同的算法,直到一个效果最好,使用预先编写好的算法是可以的,但是 strong> 应该自己尝试一下,通常没有适用于此类领域所有事物的神奇解决方案,通常每个解决方案都非常针对问题,并且根据您的需要调整不同算法的过程很长而且很难,这完全取决于您的研究和投入程度。

希望对您有所帮助!

【讨论】:

    猜你喜欢
    • 2020-07-05
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 2018-10-27
    相关资源
    最近更新 更多