使用cv2将图片转正

news/2024/11/20 9:12:20/

要点:

参考:如何用Python-OpenCV实现图片倾斜调整?


一 图片转正

比如一张纸的照片是倾斜的,用OpenCV如何实现自动检测出纸的轮廓并调整倾斜角度,让照片变“正”。

import cv2
import numpy as npdef 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)

二 透视变换demo

参考:python opencv实现图像矫正功能_python_脚本之家

import cv2
import numpy as npimg = 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 如何找到目标的4个顶点

如何找到这4个顶点:
方法有很多种,如:直线检测,轮廓检测,最小外接矩形等。

使用轮廓检测方式:

import cv2
import imutilsimg = 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 = Noneif 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 = approxbreakfor 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() 多边形逼近

重点讲解这个函数

作用:

对目标图像进行近似多边形拟合,使用一个较少顶点的多边形去拟合一个曲线轮廓,要求拟合曲线与实际轮廓曲线的距离小于某一阀值。

函数原形:

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

参数:

curve : 图像轮廓点集,一般由轮廓检测得到
epsilon : 原始曲线与近似曲线的最大距离,参数越小,两直线越接近
closed : 得到的近似曲线是否封闭,一般为True

返回值:

approxCurve :返回的拟合后的多边形顶点集。

透视变换

之前都是通过仿射变换方式,转正后截取。

但是参考了 Cropping Rotated Rectangles from Image with OpenCV
这篇文章,主要就是运用了透视变换,非常巧妙

# -*- coding: utf-8 -*-
"""File Name:     rotation_v3Description :date:          2019/5/10
"""
import cv2
import numpy as np
import matplotlib.pylab as plt
import timeimg=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)

仿射变换是二维变换,就是在一个平面上,可以通过三个定点,随意的拉拽到想要的形状,但是不能拿起来,所以他的投影还是他拉拽的本身。

透视变换 是三维变换,就是可以拿起来,随意平行、竖直、翻转一定角度等,就是可以拉拽4个定点,所以它的投影会变成不规则的形状,更高级一点。


四 根据任意矩形(四点坐标)截取指定区域图像

参考资料: 根据任意矩形(四点坐标)截取指定区域图像

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,targetelse:print("box shape is wrong ,must be list as (4,2)")return False,outputelse:print("box type is wrong,must be list as [[x1,y2],[x2,y2],[x3,y3],[x4,y4]]")return False,output

http://www.ppmy.cn/news/89104.html

相关文章

Seata AT模式源码解析二(Seata Client端启动流程)

文章目录 初始化TM和RM数据源代理 由于我们一般都是在springboot中使用的&#xff0c;而与springboot集成的我们一般就先看starter的spring.factories文件&#xff0c;看看它的自动装配 这里面主要关注SeataAutoConfiguration和SeataDataSourceAutoConfiguration。 SeataAutoCo…

2023 江西省大学生程序设计竞赛

写在前面的话&#xff1a;跟错榜了&#xff0c;死磕C题&#xff0c;又不懂sg然后就寄了。幸好队友带飞&#xff0c;最后把B题开出来了。最后六题rank18。&#xff08;这个故事告诉我们不要乱跟榜啊 比赛链接&#xff1a;https://codeforces.com/gym/104385 L 签到题&#xff…

CCIG:智能文档处理「新未来」

文章目录 ⭐️ CCIG大会简介⭐️ 领先世界的智能文档处理技术&#x1f31f; 智能图像处理&#xff1a;为文字识别 "增质提效" 筑基✨ 切边增强 - 提升文档图像质量✨ 弯曲矫正 - 解决图像畸变问题✨ 去摩尔纹 - 保证图像信息完整 &#x1f31f; 图像预处理整体效果展…

Go | zap

Go | zap 1. 简介 那些介绍、性能比较直接看参考中zap链接&#xff0c;这里只介绍该日志库用法&#xff0c;方便快速上手。 package mainimport ("go.uber.org/zap" )func main() {logger, _ : zap.NewProduction()defer logger.Sync()logger.Info("hello wo…

兼容性测试点和注意项,建议收藏

一&#xff1a;兼容性测试的概念&#xff1a;就是验证开发出来的程序在特定的运行环境中与特定的软件、硬件或数据相组合是否能正常运行、有无异常的测试过程。 二&#xff1a;兼容性测试的分类&#xff1a; &#xff08;1&#xff09;浏览器兼容性测试 指的是在浏览器上检查…

python爬虫之ajax网页抓取

在进行python爬虫时&#xff0c;我们经常会面对一些采用Ajax异步加载数据的网页&#xff0c;这种情况下&#xff0c;我们无法通过直接获取网页源代码来获取需要的数据。本文将介绍如何使用python爬虫抓取Ajax网页。 一、Ajax简介 Ajax全称为Asynchronous JavaScript and XML&…

基于RetinaNet和TensorFlow Object Detection API实现目标检测(附源码)

文章目录 一、RetinaNet原理二、RetinaNet实现1. tf.train.CheckPoint简介2. RetinaNet的TensorFlow源码 一、RetinaNet原理 待补充 二、RetinaNet实现 1. tf.train.CheckPoint简介 待补充 2. RetinaNet的TensorFlow源码 Step 1&#xff1a;安装Tensorflow 2 Object Detect…

JavaEE(系列10) -- 多线程案例3(定时器)

目录 1. 定时器 2. 标准库中的定时器 3. 实现定时器 3.1 创建带优先级的阻塞队列 3.2 创建MyTask类 3.3 构建schedule方法 3.4 构建timer类中的线程 3.5 思考 1. 定时器 定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某…