当前位置: 首页 > 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…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...