图像旋转角度计算并旋转

news2024/9/29 11:37:45
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import time

def 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 img

def CalcAngle(img):
    h, w = img.shape[:2]
    x1, y1, x2, y2 = 0, 0, 0, 0
    angle = 0
    for 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), i
        if 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), i
        if x1 != 0 and y1 != 0 and x2 != 0 and y2 != 0:
            if x2 - x1 == 0 or y2 - y1 == 0:
                print(u"不需要旋转")
                return 0
            else:
                length = (y2 - y1) / (x2 - x1)
                angle = np.arctan(length) / 0.017453
                if angle < -45:
                    angle = angle + 90
                elif angle > 45:
                    angle = angle - 90
                else:
                    pass
                print(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 np

def 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] = 255
            else:
                img[i][j] = 0
    res = 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 rect


def 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 = line
            if x2 - x1 == 0 or y2 - y1 == 0:
                print(u"不需要旋转")
                return 0
            else:
                length = (y2 - y1) / (x2 - x1)
                angle = np.arctan(length) / 0.017453
                if angle < -45:
                    angle = angle + 90
                elif angle > 45:
                    angle = angle - 90
                else:
                    pass
                print(u"旋转角度:", angle)
                return angle
    except:
        return 0

def 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 img


def 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 img


def 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] = 255
            else:
                img[i][j] = 0
    kernel = 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:
                pass
            else:
                imgout[i + 2][j + 2] = 0
    cv2.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] * height
    v = [0] * width
    hfg = [[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 = 0
    BlackNumber = 0
    for y in range(height):
        for x in range(width):
            cp = outimg[y][x]
            if cp == 0:
                linea = linea + 1
                BlackNumber += 1
            else:
                continue
        z[y] = linea
        linea = 0

    inline, start, lineNumber = 1, 0, 0
    for i in range(0, height):
        if inline == 1 and z[i] >= LineNum:
            start = i
            inline = 0
        elif (i - start > 3) and z[i] < LineNum and inline == 0:
            inline = 1
            hfg[lineNumber][0] = start - 2  # 保存行的分割位置起始位置
            hfg[lineNumber][1] = i + 2  # 保存行的分割终点位置
            lineNumber = lineNumber + 1

    lineb = 0
    for 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 + 1
                else:
                    continue
            v[x] = lineb
            lineb = 0
        incol, start1, lineNumber1 = 1, 0, 0
        z1 = hfg[p][0]
        z2 = hfg[p][1]
        for i1 in range(0, width):
            if incol == 1 and v[i1] >= LineNum1:
                start1 = i1
                incol = 0
            elif (i1 - start1 > 3) and v[i1] < LineNum1 and incol == 0:
                incol = 1
                lfg[lineNumber1][0] = start1 - 3
                lfg[lineNumber1][1] = i1 + 3
                l1 = start1 - 3
                l2 = i1 + 3
                tmp = [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, outimg


def 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] = 255
            else:
                img[i][j] = 0
    kernel = 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.coloradmin.cn/o/1409621.html

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

相关文章

【保驾护航】HarmonyOS应用开发者基础认证-题库

通过系统化的课程学习&#xff0c;熟练掌握DevEco Studio&#xff0c;ArkTS&#xff0c;ArkUI&#xff0c;预览器&#xff0c;模拟器&#xff0c;SDK等HarmonyOS应用开发的关键概念&#xff0c;具备基础的应用开发能力。 考试说明 1、考试需实名认证&#xff0c;请在考前于个…

林浩然的政治学奇幻漂流——幽默诙谐解读马基雅维利

林浩然的政治学奇幻漂流——幽默诙谐解读马基雅维利 Lin Haoran’s Whimsical Exploration of Machiavelli’s Political World 在一个阳光明媚的周末&#xff0c;我们的主人公林浩然同学决定穿越历史长河&#xff0c;踏上一场充满智识与笑声的探索之旅&#xff0c;目的地是文艺…

NineData和泽拓数据库产品Klustron完成产品兼容互认证

近日&#xff0c;云原生智能数据管理平台NineData和泽拓昆仑分布式数据库产品Klustron完成产品兼容互认证。经过严格的联合测试&#xff0c;双方软件完全相互兼容、功能完善、整体运行稳定且性能表现优异。 本次玖章算术与泽拓科技的携力合作&#xff0c;在双方共同的努力下&a…

nextjs中beforePopState使用

在某些情况下&#xff0c;希望监听popstate并在路由器对其进行操作之前执行某些操作。可以使用beforePopState。 在Next.js中&#xff0c;beforePopState是一个可选的生命周期函数&#xff0c;用于在浏览器的历史记录发生更改之前执行一些操作。具体来说&#xff0c;beforePopS…

DP读书:在常工院的2023年度总结

DarrenPig的年度总结 这是最好的时代&#xff0c;这是最坏的时代。——狄更斯 这是最好的时代&#xff0c;这是最坏的时代。——狄更斯 这是最好的时代&#xff0c;这是最坏的时代。——狄更斯 一、2023我的感受 不就是2023吗&#xff0c;不就是一年的经历吗&#xff0c;大家…

18 python快速上手

面向对象进阶 面向对象进阶1.成员1.1 变量易错点 & 面试题 1.2 方法1.3 属性 2.成员修饰符3.对象嵌套4.特殊成员总结 各位小伙伴想要博客相关资料的话关注公众号&#xff1a;chuanyeTry即可领取相关资料&#xff01; 面向对象进阶 目标&#xff1a;掌握面向对象进阶相关知识…

【JavaEE】网络编程 TCP/UDP

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…

WorkPlus移动应用管理平台,助力企业实现高效移动办公

在移动办公成为当今工作方式的主流趋势下&#xff0c;管理和运营企业移动应用成为了提高工作效率和数据安全的重要环节。而移动应用管理平台作为实现移动办公高效管理的关键工具&#xff0c;WorkPlus以其领先的性能和全面的功能&#xff0c;助力企业实现高效移动办公。 为何选…

【医学图像数据增强】切割-拼接(CS-DA)

切割-拼接CS-DA CS-DA 核心思想自然图像和医学图像之间的关键差异CS-DA 步骤确定增强后的数据数量 代码复现 CS-DA 核心思想 论文链接&#xff1a;https://arxiv.org/ftp/arxiv/papers/2210/2210.09099.pdf 大多数用于医学分割的数据增强技术最初是在自然图像上开发的&#x…

【Docker】Kubernetes 命令行 kubectl(kubectl 使用)

作者主页&#xff1a; 正函数的个人主页 文章收录专栏&#xff1a; Docker 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01; kubectl 使用 kubectl 是 Kubernetes 自带的客户端&#xff0c;可以用它来直接操作 Kubernetes。 使用格式有两种&#xff1a; kubectl […

C#hybridCLR热更新方案初探

前言 暂时处于初步研究状态&#xff0c;目前的框架使用还是尚少&#xff0c;本篇文章旨在同步给大家大概的使用流程和使用心得&#xff0c;在初步建立新项目时可以适当考虑。 介绍 热更新 与强制更新相对应&#xff0c;移动平台上App的可执行程序没有发生变化&#xff0c;仅…

免费畅享,打破写作瓶颈:星火写作助手覆盖全面,助你轻松创作

啰嗦几句 最近年终岁末&#xff0c;公司的各种文案各种总结&#xff0c;写得人是头晕脑胀&#xff0c;所以好多小伙伴最近在求智能写作的软件&#xff0c;最好是ChatGPT。 ChatGPT是国外产品&#xff0c;在国内并不能访问。而就智能写作来说&#xff0c;我们何必舍近求远呢&am…

flutter极光推送配置厂商通道(华为)笔记--进行中

一、基础集成按照下面官方文档进行 厂商通道相关参数申请教程 集成厂商 集成指南 官方文档&#xff1a;厂商通道回执配置指南 注意&#xff1a;不同厂商对app上架的要求不同&#xff0c;华为、荣耀 对app上架没有硬性要求 遇到问题 1、引入apply plugin: com.huawei.agconn…

2023-2024年重庆职业院校技能大赛“信息安全管理与评估”比赛样题

2023 年重庆职业院校技能大赛&#xff08;高等职业教育&#xff09; “信息安全管理与评估”样题任务书 第一阶段&#xff1a;任务 1 网络平台搭建&#xff08;50 分&#xff09;任务 2 网络安全设备配置与防护&#xff08;250 分&#xff09; 第二阶段&#xff1a;第一部分 网…

GoZero微服务个人探究之路(九)api文件编写总结

参考来源go-zero官方文档https://go-zero.dev/docs/tutorials 前言 go-zero是目前star最多的go语言微服务框架&#xff0c;api 是 go-zero特殊的语言&#xff0c;类型文件&#xff0c;go-zero自带的goctl可以通过.api文件生成http服务代码 api文件内容编写 不可使用关键字 …

Chrome 插件调试

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

iOS推送通知

文章目录 一、推送通知的介绍1. 简介2. 通知的分类 二、本地通知1. 本地通知的介绍2. 实现本地通知3. 监听本地通知的点击 三、远程通知1. 什么是远程通知2. 为什么需要远程通知3. 远程通知的原理4. 如何做远程通知5. 远程通知证书配置6. 获取远程推送要用的 DeviceToken7. 测试…

技术解读 | KunDB助力头部金融机构关键系统的Oracle国产替代

星环科技自主研发的分布式交易型数据库KunDB助力头部金融机构实现了关键系统的Oracle国产化替代。 通过可视化迁移工具完成了对象与数据的平滑迁移&#xff0c;将原先两套Oracle系统&#xff08;一套Oracle单机系统&#xff0c;一套Oracle RAC系统&#xff09;统一迁移到一套K…

运动戴什么耳机好?怎样选运动耳机?2024年运动蓝牙耳机推荐

​运动耳机作为运动人士的得力助手&#xff0c;不仅要求佩戴舒适&#xff0c;还需要在音质表现、防水性能、通话质量等方面有出色表现。下面我为大家推荐几款性能全面的运动耳机&#xff0c;希望能满足不同需求的运动爱好者&#xff0c;来看看吧。 1.南卡开放式耳机&#xff08…