图像旋转角度计算并旋转

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import timedef Rotate(img, angle=0.0,fill=0):"""旋转:param img:待旋转图像:param angle: 旋转角度:param fill:填充方式,默认0黑色填充:return: img: 旋转后的图像"""w, h = img.shape[:2]center = (int(w / 2), int(h / 2))rot = cv2.getRotationMatrix2D(center, angle, 1.0)img = cv2.warpAffine(img, rot, (h, w), borderValue=fill)return imgdef CalcAngle(img):h, w = img.shape[:2]x1, y1, x2, y2 = 0, 0, 0, 0angle = 0for i in range(h - 1):if img[i][int(w / 3)] == 0 and img[i - 1][int(w / 3)] != 0:# print("1",int(w/3),i)x1, y1 = int(w / 3), iif img[i][int(w * 2 / 3)] == 0 and img[i - 1][int(w * 2 / 3)] != 0:# print("2",int(w*2/3),i)x2, y2 = int(w * 2 / 3), iif x1 != 0 and y1 != 0 and x2 != 0 and y2 != 0:if x2 - x1 == 0 or y2 - y1 == 0:print(u"不需要旋转")return 0else:length = (y2 - y1) / (x2 - x1)angle = np.arctan(length) / 0.017453if angle < -45:angle = angle + 90elif angle > 45:angle = angle - 90else:passprint(u"旋转角度:", angle)return angle
starts = time.clock()img1=cv2.imread("box.jpg",0)
# img=Rotate(img1,2,255)
ret,img=cv2.threshold(img1,200,255,cv2.THRESH_BINARY)
# cv2.imshow("0",img)
img = cv2.Canny(img, 10, 255, apertureSize=3)
angle=CalcAngle(img)
img=Rotate(img1,angle)
ends = time.clock()
print("time", ends - starts, "秒")
cv2.imwrite("00.jpg",img)
# cv2.imshow("00",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

使用两张测试图片如下:

 

对于lena的图像测试结果如下:

 

另一张测试图片结果如下:

 

 也可以使用下面代码进行测试:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import cv2
import time
import numpy as npdef Location(img, tmp, threshold_value=120, dilate=3, resize_multiple=16):"""图像定位:param img: 输入原图:param tmp: 定位匹配模板:param threshold_value: 图像阈值:param dilate: 膨胀值:param resize_multiple:缩小倍率:return: rect:矩形坐标点,从右上xy到右下xy,四个值"""h, w = img.shape[:2]hy, wx = tmp.shape[:2]img = cv2.resize(img, (int(w * 1 / resize_multiple), int(h * 1 / resize_multiple)), interpolation=cv2.INTER_AREA)kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))img = cv2.erode(img, kernel, iterations=dilate)w, h = img.shape[:2]for i in range(w):for j in range(h):if img[i][j] >= threshold_value:img[i][j] = 255else:img[i][j] = 0res = cv2.matchTemplate(img, tmp, cv2.TM_SQDIFF_NORMED)min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)top_left = min_loc# bottom_right = ((top_left[0] + wx) * resize_multiple, (top_left[1] + hy) * resize_multiple)# top_left = (top_left[0] * resize_multiple, top_left[1] * resize_multiple)rect = [top_left[0] * resize_multiple, top_left[1] * resize_multiple, (top_left[0] + wx) * resize_multiple,(top_left[1] + hy) * resize_multiple]return rectdef RotateAngle(img, threshold_value=120, dilate=3,linenum=6):"""计算图像旋转角度:param img: 输入图像:param threshold_value: 阈值分割:param dilate: 膨胀值:return: angle: 旋转角度"""ret,img=cv2.threshold(img,threshold_value,255,cv2.THRESH_BINARY)img_w, img_h = img.shape[:2]# kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 2))# img = cv2.erode(img, kernel, iterations=dilate)line_widthsize = int(img_w)line_lensize = int(img_h / linenum)edges = cv2.Canny(img, 10, 255, apertureSize=3)try:lines = cv2.HoughLinesP(edges, 1, np.pi / 180, line_lensize, minLineLength=int(line_widthsize / 2),maxLineGap=line_widthsize)for line in lines[0]:# print("角度测量的直线坐标", line)x1, y1, x2, y2 = lineif x2 - x1 == 0 or y2 - y1 == 0:print(u"不需要旋转")return 0else:length = (y2 - y1) / (x2 - x1)angle = np.arctan(length) / 0.017453if angle < -45:angle = angle + 90elif angle > 45:angle = angle - 90else:passprint(u"旋转角度:", angle)return angleexcept:return 0def Rotate(img, angle=0.0):"""旋转:param img:待旋转图像:param angle: 旋转角度:return: img: 旋转后的图像"""w, h = img.shape[:2]center = (int(w / 2), int(h / 2))rot = cv2.getRotationMatrix2D(center, angle, 1.0)img = cv2.warpAffine(img, rot, (h, w), borderValue=255)return imgdef GetObject_Location(img, tmp, threshold_value=120, dilate=3, resize_multiple=16):"""旋转:param img:图像:param tmp: 模板:param threshold_value:阈值:param dilate: 膨胀值:param resize_multiple:缩放倍数:return:"""rect = Location(img, tmp, threshold_value, dilate, resize_multiple)imgout = img[rect[1]:rect[3], rect[0]:rect[2]]angle = RotateAngle(imgout, threshold_value, dilate, resize_multiple, linenum=6)img = Rotate(imgout, angle)return imgdef SaveTemple(img, file_name=".\\data\\Temple1.jpg", threshold_value=200, dilate=3, resize_multiple=16):"""模板生成存储:param img: 输入图像:param file_name: 模板保存地址:param threshold_value: 阈值分割:param dilate: 膨胀值:return: img: 保存模板图片到本地"""h, w = img.shape[:2]img = cv2.resize(img, (int(w * 1 / resize_multiple), int(h * 1 / resize_multiple)), interpolation=cv2.INTER_AREA)img_w, img_h = img.shape[:2]print(img_w, img_h)# 创建标准模板imgout = np.zeros((img_w + 4, img_h + 4, 1), np.uint8)# 图像初始化白色for i in range(img_w + 4):for j in range(img_h + 4):imgout[i][j] = 255# 图像二值化for i in range(img_w):for j in range(img_h):if img[i][j] >= threshold_value:img[i][j] = 255else:img[i][j] = 0kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))img = cv2.erode(img, kernel, iterations=dilate)for i in range(img_w):for j in range(img_h):if img[i][j] >= threshold_value:passelse:imgout[i + 2][j + 2] = 0cv2.imwrite(file_name, imgout)"""一次切割,根据投影切割"""def FirstCutting(img, Cvalue, Cerode, LineNum, LineNum1):(_, thresh) = cv2.threshold(img, Cvalue, 255, cv2.THRESH_BINARY)kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))outimg = cv2.erode(thresh, kernel, iterations=Cerode)height, width = outimg.shape[:2]z = [0] * heightv = [0] * widthhfg = [[0 for col in range(2)] for row in range(height)]lfg = [[0 for col1 in range(2)] for row1 in range(width)]Box = []linea = 0BlackNumber = 0for y in range(height):for x in range(width):cp = outimg[y][x]if cp == 0:linea = linea + 1BlackNumber += 1else:continuez[y] = linealinea = 0inline, start, lineNumber = 1, 0, 0for i in range(0, height):if inline == 1 and z[i] >= LineNum:start = iinline = 0elif (i - start > 3) and z[i] < LineNum and inline == 0:inline = 1hfg[lineNumber][0] = start - 2  # 保存行的分割位置起始位置hfg[lineNumber][1] = i + 2  # 保存行的分割终点位置lineNumber = lineNumber + 1lineb = 0for p in range(0, lineNumber):for x in range(0, width):for y in range(hfg[p][0], hfg[p][1]):cp1 = outimg[y][x]if cp1 == 0:lineb = lineb + 1else:continuev[x] = lineblineb = 0incol, start1, lineNumber1 = 1, 0, 0z1 = hfg[p][0]z2 = hfg[p][1]for i1 in range(0, width):if incol == 1 and v[i1] >= LineNum1:start1 = i1incol = 0elif (i1 - start1 > 3) and v[i1] < LineNum1 and incol == 0:incol = 1lfg[lineNumber1][0] = start1 - 3lfg[lineNumber1][1] = i1 + 3l1 = start1 - 3l2 = i1 + 3tmp = [l1, z1, l2, z2]Box.append(tmp)lineNumber1 = lineNumber1 + 1# outimg=cv2.rectangle(outimg,(l1,z1),(l2,z2),(0,255,0),1)return Box, BlackNumber, outimgdef Threshold(img, threshold, KernelValue=3, KernelValue1=(1, 1)):"""根据阈值框选:param img:输入待处理的图像:param threshold:阈值:param KernelValue:卷积核:return:outimg:输出处理后的图像"""w, h = img.shape[:2]for i in range(w):for j in range(h):"""通过设置阈值,来控制喷码花的程度"""if img[i][j] >= threshold:img[i][j] = 255else:img[i][j] = 0kernel = cv2.getStructuringElement(cv2.MORPH_RECT, KernelValue1)outimg = cv2.erode(img, kernel, iterations=KernelValue)outimg = cv2.dilate(outimg, kernel, iterations=KernelValue)return outimg"""根据投影计算出来的坐标进行数组切割"""starts = time.clock()
img = cv2.imread("lena.jpg", 0)
# img=Rotate(img,2)
angle=RotateAngle(img,200)
print(angle)
img=Rotate(img,angle)
cv2.imwrite("00.jpg",img)
ends = time.clock()
print("time", ends - starts, "秒")# img=cv2.imread("formal.bmp",0)
# SaveTemple(img)

lena结果如下:

美女图片测试结果:

说明:以上代码仅仅是讲解介绍了图像旋转的计算及矫正原理,实际上准确度受不同图像的影响较大,不过里面使用的相关图像变换的函数值得借鉴参考学习。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《幻兽帕鲁》32人专有服务器设置教程,亲测稳定

创建幻兽帕鲁服务器1分钟部署教程&#xff0c;阿里云和腾讯云均推出幻兽帕鲁服务器服务器和部署教程&#xff0c;4核16G和4核32G配置可选&#xff0c;阿腾云atengyun.com分享1分钟自建幻兽帕鲁Palworld服务器教程&#xff1a; 幻兽帕鲁服务器创建教程 幻兽帕鲁服务器官方推荐…

飞速(FS)400G产品全家福及其应用介绍

随着大型数据中心不断向更高性能、更大规模的架构演进&#xff0c;构建能够有效应对海量用户群体、智能设备激增及复杂应用负载所需的高容量网络连接已变得不可或缺。尤其是在超大规模云计算服务迅速普及的背景下&#xff0c;对具备超高带宽和微秒级低延迟特性的网络基础设施需…

灌区信息化系统的建设内容和应用

一、背景 随着科技的不断发展&#xff0c;信息化技术已经逐渐渗透到各个领域中&#xff0c;为我们的生活和工作带来了极大的便利。灌区作为农业发展的重要组成部分&#xff0c;其信息化系统的建设也日益受到重视。 二、政策 据水利部消息&#xff0c;水利部、国家发改委近日正…

Unity中URP下获取额外灯数量

文章目录 前言一、SimpleLit下额外灯数量的获取1、在 SimpleLit 下&#xff0c;先获取了额外灯的数量2、对其进行循环计算每一个额外灯3、GetAdditionalLightsCount在这里插入图片描述 二、GetAdditionalLightsCount实现了什么1、_AdditionalLightsCount.x2、unity_LightData.y…

使用python写一个比Windows系统自带浏览器更好用的计算器

【介绍】 比Windows系统自带的还好用的计算器&#xff0c;感兴趣的可以试用一下。 1.支持括号优先级运算和平方、立方计算&#xff1b; 2.支持计算历史记录功能&#xff1b; 3.支持界面缩放和拖动&#xff1b; 4.支持钉在界面&#xff08;界面最前置顶&#xff09;&#xff0c…

Qt/QML编程之路:ListView实现横排图片列表的示例(40)

ListView列表,在QML中使用非常多,排列一个行,一个列或者一个表格,都会用到ListView。 ListView显示从内置QML类型(如ListModel和XmlListModel)创建的模型中的数据,或在C++中定义的从QAbstractItemModel或QAbstract ListModel继承的自定义模型类中的数据。 ListView有一…

未来零售策略解密:品牌全球化与新兴零售模式的交汇

随着全球数字化浪潮的不断推进&#xff0c;品牌出海已经成为零售业的重要发展方向。在这个多元化、全球化的市场中&#xff0c;线上线下融合和智能零售等新兴模式正迅速崛起&#xff0c;为品牌开拓更广阔的国际市场提供了丰富的可能性。本文Nox聚星将和大家探讨新兴零售模式在全…

Windows云服务器如何配置多用户登录?(Windows 2012)华为云官方文档与视频地址

Windows云服务器如何配置多用户登录&#xff1f;&#xff08;Windows 2012&#xff09;_弹性云服务器 ECS_故障排除_多用户登录_华为云 打开任务栏左下角的“服务器管理器”&#xff0c;在左侧列表中选中“本地服务器” 然后将右侧“远程桌面”功能的选项修改为“启用”&#x…

携程这几招,让千万用户真正实现低碳出游

近日&#xff0c;法大大与企业绿色发展研究院联合发布了《2023年签约减碳与低碳办公白皮书》&#xff08;点击阅读及下载&#xff1a;法大大推出“签约减碳”年度账单&#xff0c;引领低碳办公新风潮&#xff09;&#xff0c;该白皮书基于《低碳办公评价》标准倡导的创新减碳技…

【必剪】鬼畜rap和鬼畜剧场的区别?

在【选择素材】中&#xff0c;每个素材下会有一个标签显示支持哪种的鬼畜形式&#xff0c;在点击一个两种格式的有【鬼畜剧场】和【鬼畜rap】这两中的主要区别在于 【鬼畜剧场】&#xff1a;对素材进行人工编排&#xff0c;创作自己原创的剧情作 【鬼畜rap】&#xff1a;对于素…

专业140+总分420+复旦大学957信号与系统考研经验复旦电子信息与通信

今年专业957信号与系统140&#xff0c;数二140&#xff0c;总分420&#xff0c;顺利上岸复旦大学&#xff0c;回顾这一年的复习&#xff0c;有起有落&#xff0c;也有过犹豫和放弃&#xff0c;好在都坚持下来了&#xff0c;希望大家考研复习要不忘初心&#xff0c;困难肯定是很…

win10安装postgresql 12.17

一、下载地址 Community DL Page 下载的12.17版本 二、安装 直接点“下一步、下一步”就可以&#xff0c;注意几点是在其中需要配置&#xff1a; 1.安装路径 2.data目录位置&#xff08;默认是安装路径下的data文件夹&#xff09; 3.端口&#xff08;默认5432&#xff09…

多元跨界、戮力谐老!2024深圳国际户外运动展览会再创运动生活新方式

COSP Shenzhen 2024国际户外运动用品与时尚展 2024年3.14-16日 深圳会展中心(福田馆&#xff09; COSP Shanghai 2024国际户外运动用品与时尚展 2024年9.05-07日 上海世博展览馆&#xff08;浦东&#xff09; 展会概述&#xff1a; 作为国内最具影响力的户外运动展会之一…

bt1120和bt656时序说明

时序说明 同步码说明 数据传输时序

Linux中并发程序设计(进程的创建和回收、exec函数使用)

进程的创建和回收 进程概念 概念 程序 存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09; 静态的 进程 执行一个程序所分配的资源的总称 动态的进程和程序比较 注&#xff1a;进程是存在RAM中&#xff0c;程序是存放在ROM(flash)中的进程内容 BSS段&#xff…

【数据结构与算法】栈(Stack)之 浅谈数组和链表实现栈各自的优缺点

文章目录 1.栈介绍2. 哪种结构实现栈会更优&#xff1f;3.栈代码实现&#xff08;C语言&#xff09; 往期相关文章&#xff1a; 线性表之顺序表线性表之链表 1.栈介绍 栈是一种特殊的线性表&#xff0c;只允许在栈顶&#xff08;Top&#xff09;进行插入和删除元素操作&#…

win下安装es可视化工具——elasticsearch head(win_Elasticsearch)

一、head简介 Elasticsearch Head是集群管理、数据可视化、增删改查、查询语句可视化工具。 二、node.js的安装 ElasticSearch-head 依赖于node.js 下面先安装node.js 下面是node.js下载地址http://nodejs.cn/download/&#xff1b; 下载后&#xff0c;就是一个安装包&#xf…

session反序列化

据陈腾师傅所说&#xff1a; 1.漏洞产生原因&#xff1a;写入格式和读取格式不一样。 下面是三种常见的存储格式&#xff1a; 处理器 对应的存储格式 php键名竖线经过serialize()函数序列化处理的值php_serialize(php>5.54)经…

IDEA导出jar

1、选择导出方式 2、选择Main Class 3、构建jar

sqlmap使用教程(1)-指定目标

一、sqlmap简介 sqlmap是一个自动化SQL注入测试工具&#xff0c;它支持的数据库有MySQL、MSSQL、Oracle、PostgreSQL、Access、IBM DB2、SQLite、Firebird、Sybase和SAP MaxDB。sqlmap默认使用以下5种SQL注入技术&#xff1a; 基于布尔的盲注&#xff1a;根据返回页面判断条件…