添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

一、问题的引入

opencv在图像处理方面有着非常强大的功能,当我们需要使用opencv进行一些图像的矫正工作时,我们通常需要找到原图的一些关键点,然后计算变换后的图像坐标,最后通过仿射变换或者透视变换获得自己想要的矫正图像,比如将一张拍歪了的纸进行矫正,我们的首要任务就是找到原图的一些关键点,通常的做法就是找纸张的4个顶点。

二、问题的解决方法

第一步我们肯定要找到纸张相应的矩形轮廓,这里可以二值化再找,也可以使用一些算子查找,而本文的重点是解决怎样根据矩形轮廓去确定它具体的4个顶点的位置。

使用线性规划的方法,在opencv的坐标系下使用x+y=z1和x-y=z2两条直线去切轮廓,分别当z1取最大时(x,y)是右下点,最小时是左上点;当z2取最大时(x,y)是右上点,最小时是左下点,如下图:
请添加图片描述
这个方法单独从轮廓的角度来说,只要旋转的角度不要刚刚好是45°或者135°,这个方法就没有问题,它得到的就是轮廓相对应的右下点、左上点、右上点、左下点,但不是原目标的相应点,就好像当纸张旋转超过45°时,这个方法得到的对于轮廓来说是正确的,但对于纸张来说就不对了,如下图:
请添加图片描述
这个时候如果按之前的一样进行矫正就会得到一个横放的纸张,这样里面的字都是横的,就不是我们想要的了所以这个方法要用来矫正的话,就需要对图像的旋转角度有一个计算和判断,可以通过下面代码获取角度:

#cnt:输入轮廓,angle:返回角度
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)

这个方法首先要使用轮廓获得其最小面积矩,然后观察研究矩形的性质可以根据当前的形状给出适合的x,y判断式,观察下图:
请添加图片描述

#找轮廓最小矩 cnt:轮廓  box:4个点无规律
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)

对于这样一个高比宽长的矩形,我们的方法是先将4个点按y从小到大进行排序,再取前两个按x从小到大进行排序,小的那个是左下,大的那个是右下;最后取后两个也按x从小到大进行排序,小的那个是左上,大的那个是右上。假如是一个宽比高长的矩形,我们就可以先按x的大小进行排序。这个从代码角度实现可能更为简洁,适用特定轮廓,对角度要求就更宽泛了些,除非旋转到了像上图右边一样的状况,而这种矫正一般出现的机率非常小。

三、一些实现代码

1、下面是使用方法一实现的顶点定位

import numpy as np
import cv2
def get4points(img: np.ndarray, thed, n):
    :param img  the color image which shape is [height, width, depth]
    :return 4 point locations in list or tuple, for example: [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
    #灰度和二值化
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray,thed,255,cv2.THRESH_BINARY)
    # 搜索轮廓
    contours, hierarchy = cv2.findContours(
        binary,
        cv2.RETR_LIST,
        cv2.CHAIN_APPROX_SIMPLE)
    #按轮廓长度选取需要轮廓
    len_list = []
    for i in range(len(contours)):
        len_list.append(len(contours[i]))
    #选第二长的
    sy = np.argsort(np.array(len_list))[-n]
    #寻找顶点
    sum_list = []
    dif_list = []
    for i in contours[sy]:
        sum = i[0][0]+i[0][1]
        sum_list.append(sum)
        dif_list.append(i[0][0]-i[0][1])
    id_lb = np.argsort(np.array(sum_list))
    id_lb2 = np.argsort(np.array(dif_list))
    lu_id , rd_id = id_lb[0] , id_lb[-1]
    ld_id , ru_id = id_lb2[0] , id_lb2[-1]
    points = np.array([contours[sy][lu_id][0],contours[sy][rd_id][0],contours[sy][ld_id][0],contours[sy][ru_id][0]])
    return points , contours , sy

2、下面是使用方法2实现的顶点定位

def getpoints(binary: np.ndarray  , num: int ):
    # 搜索轮廓
    contours, hierarchy = cv2.findContours(
        binary,
        cv2.RETR_LIST,
        cv2.CHAIN_APPROX_SIMPLE)
    #按轮廓位置最左(x最小)选取
    x_list = []
    for i in contours:
        x_sum = 0
        for kk in i:
            x_sum += kk[0][0]
        x_av = x_sum/len(i)
        x_list.append(x_av)
    sy = np.argsort(np.array(x_list))[num]
    cnt = contours[sy]
    #找轮廓最小矩
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    return box , contours , sy
def findpoints(points):
    #区分矩形顶点位置
    point_y=sorted(points,key=lambda t:t[1])
    lu, ru =sorted(point_y[:2],key=lambda t:t[0])
    ld, rd =sorted(point_y[2:],key=lambda t:t[0])
    return [list(lu), list(ld), list(ru),list(rd)]

3、下面是一些展示代码

#展示顶点 def show_points(img , points): point_size = 8 point_color = (0, 0, 255) # BGR thickness = 4 # 可以为 0 、4、8 points_list = [tuple(i) for i in np.int32(points).reshape(-1,2)] for point in points_list: cv2.circle(img, point, point_size, point_color, thickness) img = cv2.resize(img,(808,808)) cv2.imshow('img',img) cv2.waitKey(0) cv2.destroyAllWindows() # cv2.imwrite('dd.jpg',img) #展示轮廓 def show_Contour(img , contours , sy): cv2.drawContours(img, contours , sy , (25, 254, 0), 4) img = cv2.resize(img,(808,808)) cv2.imshow('img',img) cv2.waitKey(0) cv2.destroyAllWindows() # cv2.imwrite('mm.jpg',img) 一、问题的引入opencv在图像处理方面有着非常强大的功能,当我们需要使用opencv进行一些图像的矫正工作时,我们通常需要找到原图的一些关键点,然后计算变换后的图像坐标,最后通过仿射变换或者透视变换获得自己想要的矫正图像,比如将一张拍歪了的纸进行矫正,我们的首要任务就是找到原图的一些关键点,通常的做法就是找纸张的4个顶点。二、问题的解决方法第一步我们肯定要找到纸张相应的矩形轮廓,这里可以二值化再找,也可以使用一些算子查找,而本文的重点是解决怎样根据矩形轮廓去确定它具体的4个顶点的位置。方法一:使 #include "Math.h" #define max_corners 4#define C CV_PI /3 int Otsu(IplImage* src);int main(int argc, char*argv[]) IplImage* img = cvL
轮廓检测引言 在计算机视觉中,轮廓检测是一个十分重要的任务。与边缘不同,图像中的轮廓包含更多的实际意义。OpenCV提供了 findContours() 函数和 drawContours() 函数实现轮廓检测和绘制————————————————————OpenCV轮廓检测的例子# -*- coding:utf-8 -*-import cv2# Step1. 读入图像 image = cv2.i
1. 通过`cv2.findContours()`函数找到轮廓并筛选出矩形轮廓。 2. 计算矩形轮廓的面积,筛选出面积最大的矩形轮廓。 3. 使用`cv2.approxPolyDP()`函数对矩形轮廓进行多边形逼近,得到一个近似的多边形轮廓。 4. 对多边形轮廓进行排序,找到左上角、右上角、右下角、左下角四个顶点。 下面是一个示例代码: ``` python import cv2 import numpy as np # 读取图像并转为灰度图像 img = cv2.imread("test.png") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 对图像进行二值化处理 _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 查找轮廓 contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选矩形轮廓 rect_contours = [] for contour in contours: area = cv2.contourArea(contour) if area > 1000: perimeter = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True) if len(approx) == 4: rect_contours.append(approx) # 计算面积最大的矩形轮廓 max_area = 0 max_contour = None for contour in rect_contours: area = cv2.contourArea(contour) if area > max_area: max_area = area max_contour = contour # 对多边形轮廓进行排序,找到四个顶点 top_left = None top_right = None bottom_right = None bottom_left = None if max_contour is not None: points = max_contour.reshape(4, 2) rect = np.zeros((4, 2), dtype=np.float32) s = points.sum(axis=1) rect[0] = points[np.argmin(s)] rect[2] = points[np.argmax(s)] diff = np.diff(points, axis=1) rect[1] = points[np.argmin(diff)] rect[3] = points[np.argmax(diff)] top_left = rect[0] top_right = rect[1] bottom_right = rect[2] bottom_left = rect[3] # 在图像上绘制矩形顶点 cv2.drawContours(img, [max_contour], 0, (0, 255, 0), 2) cv2.circle(img, tuple(top_left), 5, (0, 0, 255), -1) cv2.circle(img, tuple(top_right), 5, (0, 0, 255), -1) cv2.circle(img, tuple(bottom_right), 5, (0, 0, 255), -1) cv2.circle(img, tuple(bottom_left), 5, (0, 0, 255), -1) # 显示结果 cv2.imshow("Result", img) cv2.waitKey(0) 在这个示例中,我们首先读取图像并将其转为灰度图像,在二值化处理后查找轮廓。然后筛选出面积最大的矩形轮廓,并对其进行多边形逼近。接下来对多边形轮廓进行排序,找到四个顶点,并在图像上绘制矩形顶点。 请注意,在实际应用中,由于图像中可能会有多个矩形轮廓,需要根据实际情况进行筛选和排序,以确保找到正确的顶点