图像旋转角度计算并旋转

#!/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.mfbz.cn/a/346746.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[已解决]504 Gateway Time-out 网关超时

文章目录 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时思路解决 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时 思路 网上的常规思路是修改nginx配置文件,增加请求执行时间,试过没有用 keepalive_timeout 600; fastcgi_con…

凭服务出圈的海底捞,竟然在这件事上也很卷

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

qt-C++笔记之命令行编译程序,特别是使用Q_OBJECT宏包含了moc(Meta-Object Compiler)的情况

qt-C笔记之命令行编译程序&#xff0c;特别是使用Q_OBJECT宏包含了moc(Meta-Object Compiler)的情况 —— 杭州 2024-01-24 code review! 文章目录 qt-C笔记之命令行编译程序&#xff0c;特别是使用Q_OBJECT宏包含了moc(Meta-Object Compiler)的情况1.问题现象&#xff1a;q…

eNSP学习——交换机配置Trunk接口

目录 原理概述 实验内容 实验目的 实验步骤 实验拓扑 实验编址&#xff1a; 试验步骤 基本配置 创建VLAN&#xff0c;配置Access接口 配置Trunk接口 思考题 原理概述 在以太网中&#xff0c;通过划分VLAN来隔离广播域和增强网络通信的安全性。以太网通常由多台交换机组…

架构师之路(十五)计算机网络(网络层协议)

前置知识&#xff08;了解&#xff09;&#xff1a;计算机基础。 作为架构师&#xff0c;我们所设计的系统很少为单机系统&#xff0c;因此有必要了解计算机和计算机之间是怎么联系的。局域网的集群和混合云的网络有啥区别。系统交互的时候网络会存在什么瓶颈。 ARP协议 地址解…

水雾发生器走过路过不要错过

一、细水雾灭火机理与结构特征如下&#xff1a; 瓦斯输送管道细水雾发生器&#xff0c;是根据细水雾灭火机理及煤矿瓦斯的燃烧特性而进行研制的。其灭火机理&#xff1a; 一是冷却&#xff0c;细水雾颗粒容易气化&#xff0c;大量吸热&#xff0c;迅速降温&#xff0c;终止燃烧…

【JavaWeb】会话管理 cookie session 三大域对象总结

文章目录 会话管理一、Cookie1.1 Cookie的使用1.2 Cookie的时效性1.3 Cookie的提交路径 二、Session2.1 HttpSession的使用2.2 HttpSession时效性 三、三大域对象3.1 域对象概述3.2 域对象的使用 总结 会话管理 HTTP是无状态协议 无状态就是不保存状态,即无状态协议(stateless)…

解决Sublime Text V3.2.2中文乱码问题

目录 中文乱码出现情形通过安装插件来解决乱码问题 中文乱码出现情形 打开一个中文txt文件&#xff0c;显示乱码&#xff0c;在File->Reopen With Encoding里面找不到支持简体中文正常显示的编码选项。 通过安装插件来解决乱码问题 安装Package Control插件 打开Tool->…

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

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

【项目日记(四)】第一层: 线程缓存的具体实现

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你做项目   &#x1f51d;&#x1f51d; 开发环境: Visual Studio 2022 项目日…

Unity中URP下获取每一个额外灯数据

文章目录 前言一、我们先来看一下 SimpleLit 中的调用二、获取额外灯索引1、非移动平台2、非GLES平台3、大多数平台 三、获取额外灯数据 前言 在上一篇文章中&#xff0c;我们知道了URP下是怎么获取额外灯数量的。 Unity中URP下获取额外灯数量 在这篇文章中&#xff0c;我们…

场内基金出货是什么意思?出货和洗盘有什么区别?

场内基金出货是股市中常见的一种操作策略&#xff0c;指股市中的投资大户或者机构大量或者批次买入某只股票&#xff0c;并散发利好该股票的消息&#xff0c;导致该股票在短时间内股价升高&#xff0c;从而吸引投资散户购买该股票。等到股价上升到一定的阶段时&#xff0c;庄家…

nextjs中beforePopState使用

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

两千字讲明白java中instanceof关键字的使用!

写在开头 在过往的内容中&#xff0c;我们讲了不少的Java关键字&#xff0c;比如final、static、this、super等等&#xff0c;Java中的关键字非常之多&#xff0c;下图是整理的关键字集合 而我们今天要学习的就是其中的instanceof关键字&#xff01; instanceof的定义 instanc…

k8s安全机制

安全机制&#xff1a;k8s的安全机制&#xff0c;分布式集群管理工具&#xff0c;就是容器编排。 安全机制的核心&#xff1a;API SERVER作为整个集群内部通信的中介&#xff0c;也是外控控制的入口。所有的安全机制都是围绕api server来进行设计&#xff1a; 请求api资源&#…

数据结构·单链表

不可否认的是&#xff0c;前几节我们讲解的顺序表存在一下几点问题&#xff1a; 1. 中间、头部的插入和删除&#xff0c;需要移动一整串数据&#xff0c;时间复杂度O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗 3. 增容一般是2倍的增…

MySQL安装及可视化工具SQLyog下载

编程如画&#xff0c;我是panda&#xff01; 最近学习Web开发的时候要用到数据库&#xff0c;一开始下载的ZIP版本的&#xff0c;还得修改配置文件&#xff0c;挺麻烦的&#xff0c;后来发现可以直接使用msi版的安装包疯狂next&#xff0c;所以就出一期教程。 前言 MySQL 是一…

链表--104. 二叉树的最大深度/medium 理解度A

104. 二叉树的最大深度 1、题目2、题目分析3、复杂度最优解代码示例4、适用场景 1、题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,n…

22款奔驰GLS450升级香氛负离子车载香薰功能

奔驰原厂香氛系统激活原车自带系统&#xff0c;将香气加藏储物盒中&#xff0c;通过系统调节与出风口相结合&#xff0c;再将香味传达至整个车厢&#xff0c;达到净化车厢空气的效果&#xff0c;让整个车厢更加绿色健康&#xff0c;清新淡雅。星骏汇小许Xjh15863 产品功能&…

Vue3+Vite使用Puppeteer进行SEO优化(SSR+Meta)

1. 背景 【笑小枫】https://www.xiaoxiaofeng.com上线啦 资源持续整合中&#xff0c;程序员必备网站&#xff0c;快点前往围观吧~ 我的个人博客【笑小枫】又一次版本大升级&#xff0c;虽然知道没有多少访问量&#xff0c;但我还是整天没事瞎折腾。因为一些功能在Halo上不太好实…
最新文章