赞
踩
src:源图像中待测矩形的四点坐标
sdt:目标图像中矩形的四点坐标
cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) --> dst
src:输入图像 dst:输出图像
M:2×3的变换矩阵
dsize:变换后输出图像尺寸
flag:插值方法
borderMode:边界像素外扩方式
borderValue:边界像素插值,默认用0填充
变换矩阵M可通过cv2.getAffineTransfrom(points1, points2)函数获得
变换矩阵的获取需要至少三组变换前后对应的点坐标,设取原图上的三个点组成矩阵points1,变换后的三个点组成的矩阵points2
- points1 = np.float32([ [30,30], [100,40], [40,100] ])
- points2 = np.float32([ [60,60], [40,100], [80,20] ])
-
- M = cv2.getAffineTransform(points1, points2)
- = array([[-0.33333333, 0.33333333, 60. ],
- [ 0.66666667, -0.66666667, 60. ]])
-
- Affine_img = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]))
cv2.warpPerspective(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) --> dst
其相关参数和cv2.warpAffine函数的类似,不再做介绍
它的变换矩阵可以通过cv2.getPerspectiveTransform()函数获得,其原理和cv2.getAffineTransfrom()相同,只是投射变换至少需要四组变换前后对应的点坐标,设取原图上的四个点组成矩阵points1,变换后的四个点组成的矩阵points2
如:
- points1 = np.float32([ [30,30], [10,40], [40,10], [5,15] ])
- points2 = np.float32([ [0,0], [400,0], [0,400], [400,400] ])
-
- M = cv2.getPerspectiveTransform(points1, points2)
- = array([[-9.08777969e+00, -4.54388985e+00, 4.08950086e+02],
- [-5.37005164e+00, -1.07401033e+01, 4.83304647e+02],
- [-1.15318417e-02, -1.35972461e-02, 1.00000000e+00]])
-
- Perspective_img = cv2.warpPerspective(img, M, (img.shape[1], img.shape[0]))
- # -*- coding: utf-8 -*-
- """
- @author: yuki_ho
- """
-
- import cv2
- import numpy as np
-
- # -----------------------鼠标操作相关------------------------------------------
- lsPointsChoose = []
- tpPointsChoose = []
- pointsCount = 0
- count = 0
- pointsMax = 6
-
-
- def on_mouse(event, x, y, flags, param):
- global img, point1, point2, count, pointsMax
- global lsPointsChoose, tpPointsChoose # 存入选择的点
- global pointsCount # 对鼠标按下的点计数
- global img2, ROI_bymouse_flag
- img2 = img.copy() # 此行代码保证每次都重新再原图画 避免画多了
- # -----------------------------------------------------------
- # count=count+1
- # print("callback_count",count)
- # --------------------------------------------------------------
-
- if event == cv2.EVENT_LBUTTONDOWN: # 左键点击
- pointsCount = pointsCount + 1
- # 为了保存绘制的区域,画的点稍晚清零
- # if (pointsCount == pointsMax + 1):
- # pointsCount = 0
- # tpPointsChoose = []
- print('pointsCount:', pointsCount)
- point1 = (x, y)
- print(x, y)
- # 画出点击的点
- cv2.circle(img2, point1, 10, (0, 255, 0), 2)
-
- # 将选取的点保存到list列表里
- lsPointsChoose.append([x, y]) # 用于转化为darry 提取多边形ROI
- tpPointsChoose.append((x, y)) # 用于画点
- # ----------------------------------------------------------------------
- # 将鼠标选的点用直线连起来
- print(len(tpPointsChoose))
- for i in range(len(tpPointsChoose) - 1):
- print('i', i)
- cv2.line(img2, tpPointsChoose[i], tpPointsChoose[i + 1], (0, 0, 255), 2)
- # ----------------------------------------------------------------------
- # ----------点击到pointMax时可以提取去绘图----------------
-
- cv2.imshow('src', img2)
-
- # -------------------------右键按下清除轨迹-----------------------------
- if event == cv2.EVENT_RBUTTONDOWN: # 右键点击
- print("right-mouse")
- pointsCount = 0
- tpPointsChoose = []
- lsPointsChoose = []
- print(len(tpPointsChoose))
- for i in range(len(tpPointsChoose) - 1):
- print('i', i)
- cv2.line(img2, tpPointsChoose[i], tpPointsChoose[i + 1], (0, 0, 255), 2)
- cv2.imshow('src', img2)
-
- # -------------------------双击 结束选取-----------------------------
- if event == cv2.EVENT_LBUTTONDBLCLK:
- # -----------绘制感兴趣区域-----------
- ROI_byMouse()
- ROI_bymouse_flag = 1
- lsPointsChoose = []
-
-
- def ROI_byMouse():
- global src, ROI, ROI_flag, mask2
- mask = np.zeros(img.shape, np.uint8) # (450, 800, 3)
- pts = np.array([lsPointsChoose], np.int32) # pts是多边形的顶点列表(顶点集)
- pts = pts.reshape((-1, 1, 2))
-
- print(pts) #所勾选的坐标
-
- # 这里 reshape 的第一个参数为-1, 表明这一维的长度是根据后面的维度的计算出来的。
- # OpenCV中需要先将多边形的顶点坐标变成顶点数×1×2维的矩阵,再来绘制
-
- # --------------画多边形---------------------
- mask = cv2.polylines(mask, [pts], True, (255, 255, 255))
- ##-------------填充多边形---------------------
- mask2 = cv2.fillPoly(mask, [pts], (255, 255, 255))
-
-
- cv2.imshow('mask', mask2)
- cv2.imwrite('mask.jpg', mask2)
-
- contours, hierarchy = cv2.findContours(cv2.cvtColor(mask2, cv2.COLOR_BGR2GRAY), cv2.RETR_TREE,
- cv2.CHAIN_APPROX_NONE)
- ROIarea = cv2.contourArea(contours[0])
- print("ROIarea:", ROIarea)
- ROI = cv2.bitwise_and(mask2, img)
- # cv2.imwrite('ROI.jpg', ROI)
- cv2.imshow('ROI', ROI)
-
- #暂时 下面 只针对 3 或 4 个点
- crop_change = transform4pts(ROI, pts, ROI.shape) if len(pts) > 3 else transform3pts(ROI, pts, ROI.shape)
- cv2.imshow('ROI_trans', crop_change)
-
-
- def ROI_test(img_path):
-
- img = cv2.imread(img_path)
-
- # 自己定义坐标点
- pts = np.array(
- [[[359,96]],
- [[739,97]],
- [[1164,661]],
- [[83,663]]
- ])
-
- crop_img = cropFill(img, pts)
- cv2.imshow('crop_img', crop_img)
-
- crop_change = transform4pts(crop_img, pts, crop_img.shape) if len(pts) > 3 else transform3pts(crop_img, pts, crop_img.shape)
- cv2.imshow('trans_img', crop_change)
-
- cv2.waitKey(0)
- cv2.destroyAllWindows()
-
-
- # 截取并填充
- def cropFill(src_img, pts):
-
- mask = np.zeros(src_img.shape, np.uint8) # 空的画板
-
- # --------------画多边形---------------------
- mask = cv2.polylines(mask, [pts], True, (255, 255, 255))
- ##-------------填充多边形---------------------
- mask2 = cv2.fillPoly(mask, [pts], (255, 255, 255))
-
- contours, hierarchy = cv2.findContours(cv2.cvtColor(mask2, cv2.COLOR_BGR2GRAY), cv2.RETR_TREE,
- cv2.CHAIN_APPROX_NONE)
-
- ROI = cv2.bitwise_and(mask2, src_img)
-
- return ROI
-
- # 3点 透视变换
- def transform3pts(src_img, pts, out_size):
- # print(out_size) #(730, 1176, 3) # H W
- pts = pts.astype(np.float32)
-
- # 自定义吧
- dpts = np.array([
- [0, 0],
- [out_size[1], 0],
- [out_size[1], out_size[0]],
- ], dtype=np.float32)
-
-
- M = cv2.getAffineTransform(pts, dpts)
- img_result = cv2.warpAffine(src_img, M , (out_size[1],out_size[0])) #透视变换
-
- return img_result
-
- # 4点 透视变换
- def transform4pts(src_img, pts, out_size):
- # print(out_size) #(730, 1176, 3) # H W
- pts = pts.astype(np.float32)
-
- # 自定义吧
- dpts = np.array([
- [0, 0],
- [out_size[1], 0],
- [out_size[1], out_size[0]],
- [0, out_size[0]],
- ], dtype=np.float32)
-
- M = cv2.getPerspectiveTransform(pts, dpts) #变换矩阵 ABC变换到A'B'C'
- img_result = cv2.warpPerspective(src_img, M , (out_size[1],out_size[0])) #透视变换
-
- return img_result
-
- if __name__ == '__main__':
-
- img = cv2.imread('6.jpg') #1176,730
- # ---------------------------------------------------------
- # --图像预处理,设置其大小
- # height, width = img.shape[:2]
- # size = (int(width * 0.3), int(height * 0.3))
- # img = cv2.resize(img, size, interpolation=cv2.INTER_AREA)
- # ------------------------------------------------------------
- ROI = img.copy()
- cv2.namedWindow('src')
- cv2.setMouseCallback('src', on_mouse)
- cv2.imshow('src', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
-
- # ROI_test('6.jpg')
- import argparse
- import os
- import tkinter as tk
- from tkinter import filedialog
-
- import cv2
- import numpy as np
-
- parser = argparse.ArgumentParser()
- # parser.add_argument('source', type=str)
- parser.add_argument('--height', type=int, default=1080)
- parser.add_argument('--width', type=int, default=1920)
- args = parser.parse_args()
- print(args)
-
-
- root = tk.Tk()
- root.title('不规则四边形裁剪')
-
- pos = {
- 'TL': (tk.IntVar(root, value=0), tk.IntVar(root, value=0)),
- 'TR': (tk.IntVar(root, value=0), tk.IntVar(root, value=1600)),
- 'BL': (tk.IntVar(root, value=900), tk.IntVar(root, value=0)),
- 'BR': (tk.IntVar(root, value=900), tk.IntVar(root, value=1600)),
- }
- output = (tk.IntVar(root, value=args.height), tk.IntVar(root, value=args.width))
-
- img = None
- fileName = None
- fileExtension = None
- inputRatio = None
-
-
- def mark_line(img):
- if img is None:
- return
- img_temp = img.copy()
- cv2.line(
- img_temp,
- (pos['TL'][1].get(), pos['TL'][0].get()),
- (pos['TR'][1].get(), pos['TR'][0].get()),
- (0, 0, 255), 2, cv2.LINE_AA
- )
- cv2.line(
- img_temp,
- (pos['BL'][1].get(), pos['BL'][0].get()),
- (pos['BR'][1].get(), pos['BR'][0].get()),
- (0, 0, 255), 2, cv2.LINE_AA
- )
- cv2.line(
- img_temp,
- (pos['TL'][1].get(), pos['TL'][0].get()),
- (pos['BL'][1].get(), pos['BL'][0].get()),
- (0, 0, 255), 2, cv2.LINE_AA
- )
- cv2.line(
- img_temp,
- (pos['TR'][1].get(), pos['TR'][0].get()),
- (pos['BR'][1].get(), pos['BR'][0].get()),
- (0, 0, 255), 2, cv2.LINE_AA
- )
- return img_temp
-
-
- def crop_image():
- sourcePoints = np.array([
- (pos['TL'][1].get(), pos['TL'][0].get()),
- (pos['TR'][1].get(), pos['TR'][0].get()),
- (pos['BR'][1].get(), pos['BR'][0].get()),
- (pos['BL'][1].get(), pos['BL'][0].get()),
- ], dtype=np.float32)
- print(sourcePoints)
- dstPoints = np.array([
- [0, 0],
- [output[1].get(), 0],
- [output[1].get(), output[0].get()],
- [0, output[0].get()],
- ], dtype=np.float32)
- print('output',output)
- print(dstPoints)
-
- M = cv2.getPerspectiveTransform(sourcePoints, dstPoints)
- print('M:',M)
- print('zuobiao:',(output[1].get(), output[0].get()) )
- img_result = cv2.warpPerspective(img, M, (output[1].get(), output[0].get()))
- return img_result
-
-
- def show_images():
- if img is None:
- return
-
- resize_img_to_show('input', mark_line(img))
- resize_img_to_show('output', crop_image(), small=True)
- cv2.setMouseCallback('input', mouseClicked)
-
-
- def resize_img_to_show(name, img_temp, small=False):
- if img_temp is None:
- return
- height = img_temp.shape[0]
- width = img_temp.shape[1]
- if small and height <= 700:
- ratio = 1
- else:
- ratio = 700 / height
- height = int(height * ratio)
- width = int(width * ratio)
- cv2.imshow(name, cv2.resize(img_temp, (width, height)))
-
- if name == 'input':
- global inputRatio
- inputRatio = ratio
-
-
- def openFile():
- global img, fileName, fileExtension
- file_path = filedialog.askopenfilename()
- print(file_path)
- if file_path is not None:
- fileName = os.path.basename(file_path)
- fileExtension = os.path.splitext(file_path)[1]
-
- img = cv2.imread(file_path, cv2.IMREAD_UNCHANGED)
- pos['TL'][0].set(0)
- pos['TL'][1].set(0)
- pos['TR'][0].set(0)
- pos['TR'][1].set(img.shape[1] - 1)
- pos['BL'][0].set(img.shape[0] - 1)
- pos['BL'][1].set(0)
- pos['BR'][0].set(img.shape[0] - 1)
- pos['BR'][1].set(img.shape[1] - 1)
- show_images()
-
-
- def saveFile():
- global img
- if img is None:
- return
- out_path = filedialog.asksaveasfilename(
- filetypes=[
- ('PNG File', '*.png'),
- ('JPEG File', '*.jpg'),
- ('All files', '*'),
- ],
- initialfile=fileName,
- defaultextension=fileExtension,
- )
- print(out_path)
- if out_path:
- img_result = crop_image()
- cv2.imwrite(out_path, img_result)
-
-
- def changePos(corner, xy, diff):
- def wrapper():
- pos[corner][xy].set(pos[corner][xy].get() + diff)
- show_images()
- return wrapper
-
-
- def changeOutput(xy, diff):
- def wrapper():
- output[xy].set(output[xy].get() + diff)
- show_images()
- return wrapper
-
-
- def mouseClicked(event, p1, p0, flags, param):
- if event == cv2.EVENT_LBUTTONDOWN or (event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON)):
- p0 = int(p0 / inputRatio)
- p1 = int(p1 / inputRatio)
-
- print(p0, p1)
- minDis = 1e9
- minCorner = None
- for corner in pos:
- tempDis = (pos[corner][0].get() - p0)**2 + (pos[corner][1].get() - p1)**2
- if tempDis < minDis:
- minDis = tempDis
- minCorner = corner
-
- pos[minCorner][0].set(p0)
- pos[minCorner][1].set(p1)
- show_images()
-
-
- ROW = 0
- tk.Button(root, text='Open File', command=openFile).grid(row=ROW, column=0, columnspan=2, sticky='W')
-
- for xy in [0, 1]:
- ROW += 1
- COL = -1
- for corner in ['TL', 'TR']:
- COL += 1
- tk.Label(root, text='{}{}'.format(corner, xy)).grid(row=ROW, column=COL)
- COL += 1
- tk.Entry(root, textvariable=pos[corner][xy]).grid(row=ROW, column=COL)
- for diff in [1, 10, 100]:
- COL += 1
- tk.Button(root, text=' {:+d} '.format(-diff), command=changePos(corner, xy, -diff)).grid(row=ROW, column=COL)
- COL += 1
- tk.Button(root, text=' {:+d} '.format(+diff), command=changePos(corner, xy, +diff)).grid(row=ROW, column=COL)
-
- ROW += 1
- tk.Label(root, text='').grid(row=ROW, column=0)
-
- for xy in [0, 1]:
- ROW += 1
- COL = -1
- for corner in ['BL', 'BR']:
- COL += 1
- tk.Label(root, text='{}{}'.format(corner, xy)).grid(row=ROW, column=COL)
- COL += 1
- tk.Entry(root, textvariable=pos[corner][xy]).grid(row=ROW, column=COL)
- for diff in [1, 10, 100]:
- COL += 1
- tk.Button(root, text=' {:+d} '.format(-diff), command=changePos(corner, xy, -diff)).grid(row=ROW, column=COL)
- COL += 1
- tk.Button(root, text=' {:+d} '.format(+diff), command=changePos(corner, xy, +diff)).grid(row=ROW, column=COL)
-
- ROW += 1
- tk.Label(root, text='').grid(row=ROW, column=0)
-
- ROW += 1
- COL = -1
- for xy in [0, 1]:
- COL += 1
- tk.Label(root, text='Out{}'.format(xy)).grid(row=ROW, column=COL)
- COL += 1
- tk.Entry(root, textvariable=output[xy]).grid(row=ROW, column=COL)
- for diff in [1, 10, 100]:
- COL += 1
- tk.Button(root, text=' {:+d} '.format(-diff), command=changeOutput(xy, -diff)).grid(row=ROW, column=COL)
- COL += 1
- tk.Button(root, text=' {:+d} '.format(+diff), command=changeOutput(xy, +diff)).grid(row=ROW, column=COL)
-
- ROW += 1
- tk.Button(root, text='Save File', command=saveFile).grid(row=ROW, column=0, columnspan=2, sticky='W')
-
- root.mainloop()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。