利用python --- 图像中矩形框识别替换

目录

(一)功能说明

孩子的数字图像处理的课程大作业。题目要求:

  • 1. 拍摄一张带有自己电脑屏幕的画质清晰的照片
  • 2. 使用合适的图像处理方法准确识别出照片中的电脑屏幕
  • 3. 用另外一张图片替换图像中的电脑屏幕

(二)问题难点与核心思想

①难点一:矩形边框的检测识别(噪声)

针对难点一: 拟采用边缘检测检测像素突变点提取边缘线条+轮廓提取+拟合外接四边形寻找轮廓中满足面积条件的四边形。考虑到拍摄图像有很多噪点干扰,采用中值滤波进行平滑处理,过滤椒盐噪声。设定矩形区域面积阈值,去除不满足条件轮廓,对轮廓进行多边形拟合迭代,直到拟合成四边形,并排序输出四个点坐标。

②难点二:由于相机平面很难与物体平面平行,所以矩形区域是形变的矩形。

针对难点二: 拟采用投影变换,利用getPerspectiveTransform函数求出变换矩阵M,再用M将代替换图像投影变换到矩形区域,其余面积像素为0,以便后续图片融合相加。
利用python --- 图像中矩形框识别替换

(三)实现步骤

1.算法流程图

利用python --- 图像中矩形框识别替换

(1)图像预处理:灰度、滤波、二值化处理
# 开始图像处理,读取图片文件
image = cv2.imread(Config.src)
image_copy = image.copy()
image_mix = cv2.imread(Config.drc)
cv2.imshow("image", image)
cv2.imshow("image_mix", image_mix)
#获取原始\目标图像的大小
srcHeight,srcWidth ,channels = image.shape
drcHeight,drcWidth ,channels_drc = image_mix.shape

# 镶嵌的图的四个顶点
box_drc=np.array([[0, 0],[drcWidth, 0],[drcWidth, drcHeight],[0, drcHeight]])
dst_rect = np.float32([box_drc[0], box_drc[1], box_drc[2], box_drc[3]])
#转成灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 
# 中值滤波平滑,消除噪声
# 当图片缩小后,中值滤波的孔径也要相应的缩小,否则会将有效的轮廓擦除
binary = cv2.medianBlur(gray,Config.medianBlur_value)  
#转换为二值图像
ret, binary = cv2.threshold(binary, Config.threshold_thresh, 255, cv2.THRESH_BINARY)
cv2.imshow("binary", binary)

利用python --- 图像中矩形框识别替换

(2)边缘检测、提取轮廓、寻找外接矩形坐标
# canny 边缘检测
binary = cv2.Canny(binary, Config.canny_minvalue, Config.canny_maxvalue, apertureSize = Config.canny_apertureSize)
#显示边缘检测的结果
cv2.imshow("Canny", binary)
# 提取轮廓
contours,_ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
## 输出轮廓数目
#print("the count of contours is  %d \n"%(len(contours)))

对轮廓拟合外接四边形,寻找矩形坐标:

# 找出外接四边形, c是轮廓的坐标数组
def boundingBox(idx,c):
    if len(c) < Config.min_contours: 
        return None
    epsilon = Config.epsilon_start
    while True:
        approxBox = cv2.approxPolyDP(c,epsilon,True)
        #求出拟合得到的多边形的面积
        theArea = math.fabs(cv2.contourArea(approxBox))
        #输出拟合信息
        print("contour idx: %d ,contour_len: %d ,epsilon: %d ,approx_len: %d ,approx_area: %s"%(idx,len(c),epsilon,len(approxBox),theArea))
        if (len(approxBox) < 4):
            return None
        if theArea > Config.min_area:
            if (len(approxBox) > 4):
                # epsilon 增长一个步长值
                epsilon += Config.epsilon_step               
                continue
            else: #approx的长度为4,表明已经拟合成矩形了                
                #转换成4*2的数组
                approxBox = approxBox.reshape((4, 2))                
                return approxBox                
        else:
            print("failed to find boundingBox,idx = %d area=%f"%(idx, theArea))
            return None

#针对每个轮廓,拟合外接四边形,如果成功,则将记录该四个点
for idx,c in enumerate(contours):
    approxBox = boundingBox(idx,c)
    if approxBox is None: 
#        print("\n")
        continue
    
     # 获取最小矩形包络
    rect = cv2.minAreaRect(approxBox)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    box = box.reshape(4,2)
    box = order_points(box)
    print("boundingBox:\n",box)   

利用python --- 图像中矩形框识别替换

(3)坐标排序、投射投影变换

由于得到的四边形的四个点并不是与待替换图形的四个点是上下左右一一对应的,所以要对得到的四个点进行排序,查明各点归属位置(利用左上角的点横纵坐标和最小,而右下角的和最大,右上角的差异最小,而左下角的差异最大)。

#对坐标点进行排序
def order_points(pts):
    # 初始化将要排序的坐标列表
    # 所以列表中的第一个条目是左上角,
    # 第二条是右上角,第三条是右下角,第四条是左下角
    rect = np.zeros((4, 2), dtype="float32")

    # 左上角的和最小,而右下角的和最大
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # 计算两个点之间的差异,右上角的差异最小,而左下角的差异最大
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    # [top-left, top-right, bottom-right, bottom-left]
    return rect

得到电脑屏幕到代替换图像的投影变换矩阵M:

 # 生成透视变换矩阵,透视变换
    rect = np.array([[0, 0],[w - 1, 0],[w - 1, h - 1],[0, h - 1]],dtype="float32")
    M = cv2.getPerspectiveTransform(src_rect, rect) 

    #得到透视变换后的图像,即抓取到图像
    warped = cv2.warpPerspective(image_copy, M, (w, h)) #w和h为
    cv2.imshow("warped",warped)
    cv2.imwrite('picture_101.jpg',warped)
    print("\n")
(3)图像替换

根据变换矩阵M求取反变换矩阵,然后利用掩膜变换、图像拼接等步骤将代替换图像替换到电脑屏幕区域。

#反变换矩阵
M = cv2.getPerspectiveTransform(dst_rect, src_rect)
result_img_22 = cv2.warpPerspective(image_mix, M, (srcWidth, srcHeight))
#对目标进行镶嵌
img2gray = cv2.cvtColor(result_img_22,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 0, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
cv2.imshow('mask',mask_inv)
img1_bg = cv2.bitwise_and(image,image,mask = mask_inv)
cv2.imshow('img1_bg',img1_bg)
img2_fg = cv2.bitwise_and(result_img_22,result_img_22,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
cv2.imshow('result',dst)
cv2.imwrite('result.jpg',dst)
print('over')
cv2.waitKey(0)
cv2.destroyAllWindows()

(四)实现结果

利用python --- 图像中矩形框识别替换
利用python --- 图像中矩形框识别替换

利用python --- 图像中矩形框识别替换

利用python --- 图像中矩形框识别替换
利用python --- 图像中矩形框识别替换

上一篇:DrawPcbElement


下一篇:minAreaRect