Use cv2 to positively convert the image

Main points:

Reference: How to implement image tilt adjustment with Python-OpenCV?


A picture turned positive

For example, a photo of a piece of paper is tilted, how to use OpenCV to automatically detect the outline of the paper and adjust the tilt angle to make the photo "positive".

import cv2
import numpy as np

def click(event,x,y,flags,param):
    if event==cv2.EVENT_LBUTTONDOWN:
        if len(pts)<4:
            pts.append([x,y])# 只记录前四次鼠标左击的位置
            cv2.circle(img,(x,y),1,(0,0,0))
            cv2.imshow('img1',img)
        else:
            cv2.destroyWindow('img1')# 第五次鼠标左击直接关闭图片窗口

img=cv2.imread('files.jpg')
pts=[]
cv2.namedWindow('img1')
cv2.setMouseCallback('img1',click)
cv2.imshow('img1',img)
cv2.waitKey(0)
pts.sort(reverse=False)
print(pts)
width,height=250,350
pts1=np.float32(pts)
pts2=np.float32([[0,0],[width,0],[0,height],[width,height]])
matrix=cv2.getPerspectiveTransform(pts1,pts2)
img2=cv2.warpPerspective(img,matrix,(width,height))
cv2.imshow('img2',img2)
cv2.waitKey(0)

Two perspective transformation demo

Reference: Python opencv implements image correction function_python_Program Home

import cv2
import numpy as np
 
img = cv2.imread('/home/pzs/图片/1.jpeg')
 
result3 = img.copy()
 
img = cv2.GaussianBlur(img,(3,3),0)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 
edges = cv2.Canny(gray,50,150,apertureSize = 3)
cv2.imwrite("canny.jpg", edges)
 
src = np.float32([[207, 151], [517, 285], [17, 601], [343, 731]])
dst = np.float32([[0, 0], [337, 0], [0, 488], [337, 488]])
m = cv2.getPerspectiveTransform(src, dst)
result = cv2.warpPerspective(result3, m, (337, 488))
cv2.imshow("result", result)
cv2.waitKey(0)

2.1 How to find the 4 vertices of the target

How to find these 4 vertices:
There are many methods, such as: line detection, contour detection, minimum circumscribed rectangle, etc.

Use contour detection method:

import cv2
import imutils
 
img = cv2.imread('1.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
dilate = cv2.dilate(blurred, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)))
edged = cv2.Canny(dilate, 30, 120, 3)            # 边缘检测
 
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # 轮廓检测
cnts = cnts[0] if imutils.is_cv2() else cnts[1]  # 判断是opencv2还是opencv3
docCnt = None
 
if len(cnts) > 0:
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # 根据轮廓面积从大到小排序
    for c in cnts:
        peri = cv2.arcLength(c, True)                                       # 计算轮廓周长
        approx = cv2.approxPolyDP(c, 0.02*peri, True)           # 轮廓多边形拟合
        # 轮廓为4个点表示找到纸张
        if len(approx) == 4:
            docCnt = approx
            break
 
for peak in docCnt:
    peak = peak[0]
    cv2.circle(img, tuple(peak), 10, (255, 0, 0))
 
cv2.imshow('img', img)
cv2.waitKey(0)

2.2 cv2.approxPolyDP() polygon approximation

Focus on this function

effect:

Perform approximate polygon fitting on the target image, use a polygon with fewer vertices to fit a curve profile, and require the distance between the fitted curve and the actual profile curve to be less than a certain threshold.

Function prototype:

cv2.approxPolyDP(curve, epsilon, closed) -> approxCurve

parameter:

curve: Image contour point set, generally obtained by contour detection
epsilon: The maximum distance between the original curve and the approximate curve, the smaller the parameter, the closer the two straight lines are
Closed: Whether the obtained approximate curve is closed, generally True

return value:

approxCurve : The returned set of fitted polygon vertices.

Three perspective transformation

Before, it was through affine transformation, and it was intercepted after conversion.

But referring to the article Cropping Rotated Rectangles from Image with OpenCV
, the main thing is to use perspective transformation , which is very clever

# -*- coding: utf-8 -*-
"""
   File Name:     rotation_v3
   Description :
   date:          2019/5/10
"""
import cv2
import numpy as np
import matplotlib.pylab as plt
import time

img=cv2.imread('3_75.jpg')
# img=img[14:-15,13:-14]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("num of contours: {}".format(len(contours)))


rect = cv2.minAreaRect(contours[1])  #获取蓝色矩形的中心点、宽高、角度


'''
retc=((202.82777404785156, 94.020751953125),
 (38.13406753540039, 276.02105712890625),
 -75.0685806274414)


width = int(rect[1][0])
height = int(rect[1][1])
angle = rect[2]
print(angle)

if width < height:  #计算角度,为后续做准备
  angle = angle - 90
print(angle)
'''
if rect[-1] < -45 or rect[-1] > 45:
	rect = (rect[0], (rect[1][1], rect[1][0]), rect[2] - 90)
angle = rect[2]
width = int(rect[1][0])
height = int(rect[1][1])
# if  angle < -45:
#     angle += 90.0
#        #保证旋转为水平
# width,height = height,width
src_pts = cv2.boxPoints(rect)

# box = cv2.boxPoints(rect)
# box = np.int0(box)
# cv2.drawContours(img_box, [box], 0, (0,255,0), 2) 

dst_pts = np.array([[0, height],
                    [0, 0],
                    [width, 0],
                    [width, height]], dtype="float32")
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warped = cv2.warpPerspective(img, M, (width, height))

if angle<=-90:  #对-90度以上图片的竖直结果转正
    warped = cv2.transpose(warped)
    warped = cv2.flip(warped, 0)  # 逆时针转90度,如果想顺时针,则0改为1
    # warped=warped.transpose
cv2.imshow('wr1',warped)
cv2.waitKey(0)

Affine transformation is a two-dimensional transformation, that is, on a plane, it can be randomly dragged to the desired shape through three fixed points, but it cannot be picked up, so its projection is still the one he dragged.

Perspective transformation is a three-dimensional transformation, that is, it can be picked up, parallelized, vertically, flipped at a certain angle, etc., that is, four fixed points can be pulled, so its projection will become an irregular shape, which is a little more advanced.


4. Intercept the image of the specified area according to any rectangle (four-point coordinates)

Reference material: Intercept the image of the specified area according to any rectangle (four-point coordinates)

def CutImgeByBox(output,box):
    """
    根据任意内接矩形,四点(顺时针)box[[x1,y2],[x2,y2],[x3,y3],[x4,y4]],从输入图像中,截取图像
    """
    if type(box)==type([]):    
        pts1 = np.float32(box)
        if pts1.shape==(4,2):
            # 变换后的矩形四个顶点坐标    
            dy=int(np.sqrt((box[0][0]-box[1][0])**2+(box[0][1]-box[1][1])**2))
            dx=int(np.sqrt((box[1][0]-box[2][0])**2+(box[1][1]-box[2][1])**2))   
            pts2 = np.float32([[1, dy+1],
                          [1, 1],
                          [1+dx, 1],
                          [1+dx, 1+dy]]) 
            M = cv2.getPerspectiveTransform(pts1,pts2)
            dst = cv2.warpPerspective(output, M, (output.shape[1],output.shape[0]))   
            target = dst[int(pts2[1][1]):int(pts2[0][1]),int(pts2[1][0]):int(pts2[2][0]),:]
            return True,target
        else:
            print("box shape is wrong ,must be list as (4,2)")
            return False,output
    else:
        print("box type is wrong,must be list as [[x1,y2],[x2,y2],[x3,y3],[x4,y4]]")
        return False,output

Guess you like

Origin blog.csdn.net/March_A/article/details/130714888