当前位置: 首页 > news >正文

图像旋转角度计算并旋转

#!/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结果如下:

美女图片测试结果:

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

 

相关文章:

图像旋转角度计算并旋转

#!/usr/bin/python3 # -*- coding: utf-8 -*- import cv2 import numpy as np import timedef Rotate(img, angle0.0,fill0):"""旋转:param img:待旋转图像:param angle: 旋转角度:param fill&#xff1a;填充方式&#xff0c;默认0黑色填充:return: img: 旋转后…...

通过curl访问k8s集群获取证书或token的方式

K8S安全控制框架主要由下面3个阶段进行控制&#xff0c;每一个阶段都支持插件方式&#xff0c;通过API Server配置来启用插件。 1. Authentication&#xff08;认证&#xff09; 2. Authorization&#xff08;授权&#xff09; 3. Admission Control&#xff08;准入控制&#…...

苍穹外卖-前端部分(持续更新中)

d 第二种&#xff1a;cmd中输入 vue ui进入图形化界面选择npm,vue2进行创建 先将创建的Vue框架导入Vsocde开发工具 然后ctrshiftp 输入npm 点击serve将项目启动 下这种写法跨域会报错&#xff1a; 解决方法&#xff1a;...

windows用mingw(g++)编译opencv,opencv_contrib,并install安装

windows下用mingw编译opencv貌似不支持cuda&#xff0c;选cuda会报错&#xff0c;我无法解决&#xff0c;所以没选cuda&#xff0c;下面两种编译方式支持。 如要用msvc编译opencv&#xff0c;参考我另外一篇文章 https://blog.csdn.net/weixin_44733606/article/details/1357…...

JDWP 协议及实现

JDWP 的协议细节并通过实际调试中的例子展开揭示 JDWP 的实现机制,JDWP 是 Java Debug Wire Protocol 的缩写,它定义了调试器(debugger)和被调试的 Java 虚拟机(target vm)之间的通信协议。 JDWP 协议介绍 这里首先要说明一下 debugger 和 target vm。Target vm 中运行…...

利用ADS建立MIPI D-PHY链路仿真流程

根据MIPI D-PHY v1.2规范中对于互连电气参数的定义,本次仿真实例中,需要重点关注如下的设计参数: 1. 差分信号的插入损耗Sddij和回拨损耗Sddii; 2. 模式转换损耗Sdcxx、Scdxx; 3. 数据线与时钟线之间的串扰耦合(远、近端)。 设计者还可以结合CTS中的补充…...

【大根堆】【C++算法】871 最低加油次数

作者推荐 【动态规划】【map】【C算法】1289. 下降路径最小和 II 本文涉及知识点 大根堆 优先队列 LeetCode:871最低加油次数 汽车从起点出发驶向目的地&#xff0c;该目的地位于出发位置东面 target 英里处。 沿途有加油站&#xff0c;用数组 stations 表示。其中 statio…...

SpringBoot的自动装配原理

一、SpringBootConfiguration注解的作用 SpringBootApplication注解是SpringBoot项目的核心注解,加在启动引导类上。点击进去可以发现SpringBootApplication注解是一个组合注解。其中SpringBootConfiguration和EnableAutoConfiguration是由Spring提供的,剩下的注解是由JDK提供的…...

嵌入式驱动开发需要会哪些技能?

嵌入式驱动开发是指在嵌入式系统中编写驱动程序&#xff0c;实现设备与计算机之间的通信。嵌入式驱动开发是指编写设备驱动程序&#xff0c;实现设备与计算机之间的通信。以下是一些嵌入式驱动开发的具体操作方法: 1&#xff09;了解硬件设备结构&#xff1a;在进行嵌入式驱动…...

Leetcode:二分搜索树层次遍历

题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,…...

【fabric.js】toDataURL 性能问题、优化

必要解释&#xff1a;最好看完。。省流版的话&#xff0c;toDataURL 的 multiplier参数不要设置超过500&#xff1b; 情景&#xff1a;在做某些功能的时候涉及到图形的预览&#xff0c;预览的时候是导出为40*40 像素的图片&#xff0c;当碰到某些图形非常小的时候&#xff0c;…...

基于Grafana+Prometheus搭建可视化监控系统实践

基本介绍 Grafana&#xff1a;一个监控仪表系统&#xff0c;可以根据提供的监控数据&#xff0c;生产可视化仪表盘&#xff0c;同时也具有告警通知功能。这里的监控数据来源&#xff0c;目前主要以Prometheus为主&#xff08;也支持其它数据源&#xff09;&#xff0c;每次展现…...

选择排序(堆排序和topK问题)

选择排序 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 如果我们用扑克牌来举例&#xff0c;那么选择排序就像是提前已经把所有牌都摸完了&#xff0c;而再进行牌…...

webpack tree shaking 摇树原理

Tree-shaking 是指在打包过程中通过静态分析&#xff0c;识别并删除未使用的代码&#xff0c;以减小最终输出文件的大小。Webpack 通过内置的 UglifyJS 插件或者 Terser 插件来实现 Tree-shaking。下面是简要的 webpack Tree-shaking 的原理&#xff1a; 标记未使用的代码&…...

开源模型应用落地-业务整合篇(三)

一、前言 在之前的两篇文章中,我们学习了如何构建基本的即时消息(IM)功能。今天,我们将进一步将IM模块与AI服务进行连接,实现用户提问并由模型进行回答,最后将结果展示在用户界面上。 二、术语 2.1. Spring Boot 是一个用于快速构建基于Spring框架的Java应用程序的开源框…...

js打地鼠

文章目录 1实现效果2代码实现 1实现效果 游戏难度&#xff1a;简单&#xff0c;一般&#xff0c;困难&#xff0c;噩梦&#xff08;控制setInterval的time参数&#xff09; 按钮功能&#xff1a;结束&#xff08;可以通过修改gameScore的值来修改判定结束的分数&#xff09;&am…...

计算机网络体系架构认知--网络协议栈

文章目录 一.计算机网络分层架构各协议层和计算机系统的联系从整体上理解计算机网络通信计算机网络通信的本质 二.Mac地址,IP地址和进程端口号三.局域网通信与跨局域网通信局域网通信跨局域网通信全球互联的通信脉络 四.网络编程概述 一.计算机网络分层架构 实现计算机长距离网…...

Ubuntu 22.04 安装tomcat

tomcat是常用的Java服务容器,这篇文章我们就来讲讲如何安装它。 更新软件包 首先是更新软件包,这是最常规的操作 sudo apt update 然后是开始安装,不多一会就可以安装好了 sudo apt install tomcat9 然后看一下状态 sudo systemctl status tomcat9 发现虽然启动了,但…...

记录:Ubuntu 18.04 X86 上通过CMake 指定编译器工具链交叉编译。

最好是通过 cmake 命令行来设置&#xff0c;要不然你只有在 CMakeFiles.txt 里面自己写判断语句了。 要用 cmake 交叉编译&#xff0c;必须设置连接器&#xff0c;要不然会使用当前系统的 ld&#xff0c;就是 /usr/bin/ld。 但是其它平台是不会ld上的&#xff0c;elf格式都不…...

requests,js逆向练习

自上而下排除jquery源码&#xff0c;点进去utils 发现第一次请求是getTime 再次运行此断点才是登录&#xff0c;这个时候密码已经被加密了 查看上级js页面&#xff0c;发现加密函数 进去看函数加密过程 得到结果RSA python代码 import base64 import jsonimport requests f…...

Chrome 插件调试

http://blog.haoji.me/chrome-plugin-develop.html#te-bie-zhu-yi-background-de-bao-cuo 手把手&#xff1a;Chrome浏览器开发系列(四)&#xff1a;调试我们开发的插件 - 掘金...

云轴科技ZStack成为交通运输业上云用云推进中心首批成员单位

近日&#xff0c;中国信息通信研究院、中国交通运输协会信息专业委员会联合发起成立“交通运输业上云用云推进中心”&#xff0c;上海云轴信息科技有限公司&#xff08;简称云轴科技ZStack&#xff09;凭借优秀的产品技术创新能力和在交通运输领域的实践经验成为首批成员单位并…...

代码随想录算法训练营31期day4,力扣24+19+02.07+142

24&#xff0c;动指针 class Solution { public:ListNode* swapPairs(ListNode* head) {//建立虚拟头结点auto dummynew ListNode(-1);dummy->nexthead;for(auto pdummy;p->next&&p->next->next;){auto ap->next;auto ba->next;p->nextb;a->n…...

eNSP学习——利用单臂路由实现VLAN间路由

目录 原理概述 实验内容 实验目的 实验步骤 实验拓扑 实验编址 配置步骤 创建VLAN并配置Access、Trunk接口 配置路由器子接口和IP地址 配置路由器子接口封装VLAN 测试结果 原理概述 在以太网中&#xff0c;通常会使用VLAN技术隔离二层广播域来减少广播的影响&#…...

ISO27001认证:企业与个人发展的必备之选

ISO27001认证&#xff0c;对于企业和个人来说&#xff0c;都具有极高的价值和重要性。作为国际权威的信息安全管理体系标准&#xff0c;它为企业提供了保障信息安全、防范风险和提升竞争力的有力工具。 &#x1f4bc;对企业的价值&#xff1a; ISO27001认证可以帮助企业满足国家…...

SpringBoot使用druid

SpringBoot使用druid 一、前言二、配置1、pom依赖2、配置文件yml3、配置类 一、前言 Java程序很大一部分要操作数据库&#xff0c;为了提高性能操作数据库的时候&#xff0c;又不得不使用数据库连接池。 Druid 是阿里巴巴开源平台上一个数据库连接池实现&#xff0c;结合了 C…...

TongWeb8交流常见问答集

问题1&#xff1a;今后用到你们TongWeb产品该联系谁&#xff1f; 答复&#xff1a; 1. 商务问题&#xff0c;如&#xff1a;报价、license授权、合同等请联系销售。 2. TongWeb技术问题&#xff0c;未签项目联系售前&#xff0c;已签项目联系售后。有指定项目经理的项目&…...

GBASE南大通用分享-mysql中的load data infile用法

GBASE南大通用分享 mysql中的load data infile用法 LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE file_name.txt [REPLACE | IGNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY \t] [OPTIONALLY] ENCLOSED BY ] [ESCAPED BY \\ ]] [LINES TERMINATED BY \n] [IGNORE number L…...

Ubuntu18编译jdk8源码

环境 系统 ubuntu18 Linux ubuntu 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux jdk源码openjdk-8u41-src-b04-14_jan_2020.zip bootJdk jdk-8u391-linux-x64.tar.gz ps -e|grep ssh sudo apt-get install ssh…...

《开始使用PyQT》 第01章 PyQT入门 02 安装Python3和PyQT6

02 安装Python3和PyQT6 《开始使用PyQT》 第01章 PyQT入门 02 安装Python3和PyQT6 So that all readers are on the same page, let’s begin by installing or updating your version of Python. 为了让所有读者都能理解&#xff0c;让我们从安装或更新 Python 版本开始。 …...