python 图片倾斜校正

  1. 前言

进行图片校正是将拍照倾斜的图片恢复水平状态,大致思路为:

  1. 用canny算子检测出图像中的边缘轮廓线;
  2. 用霍夫线变换检测出图像中的所有直线;
  3. 筛选出接近水平方向上的直线,求出他们偏移角度的平均值;
  4. 根据倾斜角旋转矫正;
  5. 输出图片。

这里设计到几个知识点:
canny算子
原理:数字图像处理(20): 边缘检测算子(Canny算子)
cv2.Canny函数:OpenCV-Python教程(8、Canny边缘检测)
edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])

变量内容image要检测的图像

threshold1 和 threshold2 的值较小时,能够捕获更多的边缘信息,下文中canny_threshold(self, img_path)函数即可可视化不同threshold的效果。

霍夫变换
原理:霍夫变换——神奇的特征提取算法
cv2.HoughLines函数:每天一练P9-Python和OpenCV做图像处理(HoughLines)

其他
Python2 math.degrees() 函数
Python scipy.ndimage.rotate用法及代码示例(该函数是按逆时针旋转)
利用向量推导坐标旋转公式(方案一)
atctan

  1. 代码

在使用代码前,canny的阈值一定要根据实际情况修改!

import cv2
import math
import numpy as np
from scipy import ndimage

class HorizontalCorrection:
    def __init__(self):
        self.rotate_vector = np.array([0, 1])
        self.rotate_theta = 0

    def process(self, img):
        img = cv2.imread(img)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        edges = cv2.Canny(gray, 350, 400, apertureSize=3)
        cv2.imwrite('./test result/edges.png', edges)

        lines = cv2.HoughLines(edges, 1, np.pi / 180, 120)
        sum = 0
        count = 0
        for i in range(len(lines)):
            for rho, theta in lines[i]:
                a = np.cos(theta)
                b = np.sin(theta)
                x0 = a * rho
                y0 = b * rho
                x1 = int(x0 + 1000 * (-b))
                y1 = int(y0 + 1000 * (a))
                x2 = int(x0 - 1000 * (-b))
                y2 = int(y0 - 1000 * (a))

                if x2 != x1:
                    t = float(y2 - y1) / (x2 - x1)
                    if t  np.pi / 5 and t >= - np.pi / 5:
                        rotate_angle = math.degrees(math.atan(t))
                        sum += rotate_angle
                        count += 1
                        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

        if count == 0:
            avg_rotate_angle = 0
        else:
            avg_rotate_angle = sum / count
        self.rotate_img = ndimage.rotate(img, avg_rotate_angle)

        self.rotate_theta = avg_rotate_angle
        self.count_rotate_vector()

    def count_rotate_vector(self):
        v1_new = (self.rotate_vector[0] * np.cos(self.rotate_theta / 180)) - \
                 (self.rotate_vector[1] * np.sin(self.rotate_theta / 180))
        v2_new = (self.rotate_vector[1] * np.cos(self.rotate_theta / 180)) + \
                 (self.rotate_vector[0] * np.sin(self.rotate_theta / 180))
        self.rotate_vector = np.array([v1_new, v2_new])

    def manual_set_rotate_vector(self, rotate_theta):
        self.rotate_theta = rotate_theta
        self.count_rotate_vector()

    def canny_threshold(self, img_path):
        img_original = cv2.imread(img_path)

        cv2.namedWindow('Canny')

        def nothing(x):
            pass

        cv2.createTrackbar('threshold1','Canny',50,400,nothing)
        cv2.createTrackbar('threshold2','Canny',100,400,nothing)
        while(1):

            threshold1=cv2.getTrackbarPos('threshold1','Canny')
            threshold2=cv2.getTrackbarPos('threshold2','Canny')

            img_edges=cv2.Canny(img_original,threshold1,threshold2)

            cv2.imshow('original',img_original)
            cv2.imshow('Canny',img_edges)
            if cv2.waitKey(1)==ord('q'):
                break
        cv2.destroyAllWindows()

if __name__ == '__main__':
    horizontal_correction = HorizontalCorrection()

    horizontal_correction.process(r'./test image/IMG_6386.JPG')
    print(horizontal_correction.rotate_theta)
    cv2.imwrite('./test result/1.png', horizontal_correction.rotate_img)
    cv2.imshow('rotate', horizontal_correction.rotate_img)
    cv2.waitKey()
  1. 效果图

python 图片倾斜校正

python 图片倾斜校正

从图中可以看出霍夫变换根据栏杆的水平线进行校正。
彩蛋:乾元的朋友,让我看见你们的双手。

; 补充——用滑动条调整canny阈值

之前在一个博客看到的,但是现在找不到了,先把代码放上。

    def canny_threshold(self, img_path):
        img_original = cv2.imread(img_path)

        cv2.namedWindow('Canny')

        def nothing(x):
            pass

        cv2.createTrackbar('threshold1', 'Canny', 50, 400, nothing)
        cv2.createTrackbar('threshold2', 'Canny', 100, 400, nothing)
        while True:

            threshold1 = cv2.getTrackbarPos('threshold1', 'Canny')
            threshold2 = cv2.getTrackbarPos('threshold2', 'Canny')

            img_edges = cv2.Canny(img_original, threshold1, threshold2)

            cv2.imshow('original', img_original)
            cv2.imshow('Canny', img_edges)
            if cv2.waitKey(1) == ord('q'):
                break
        cv2.destroyAllWindows()

其他

cv2.HoughLines返回值的处理方式进行了修改。

import cv2
import math
import numpy as np
from scipy import ndimage

class HorizontalCorrection:
    def __init__(self):
        self.rotate_vector = np.array([0, 1])
        self.rotate_theta = 0

    def process(self, img):
        img = cv2.imread(img)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        edges = cv2.Canny(gray, 350, 400, apertureSize=3)
        cv2.imwrite('./test result/edges.png', edges)

        lines = cv2.HoughLines(edges, 1, np.pi / 180, 120)
        sum = 0
        count = 0
        for r_theta in lines:
            arr = np.array(r_theta[0], dtype=np.float64)
            rho, theta = arr
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a * rho
            y0 = b * rho
            x1 = int(x0 + 1000 * (-b))
            y1 = int(y0 + 1000 * (a))
            x2 = int(x0 - 1000 * (-b))
            y2 = int(y0 - 1000 * (a))

            if x2 != x1:
                t = float(y2 - y1) / (x2 - x1)
                if t  np.pi / 5 and t >= - np.pi / 5:
                    rotate_angle = math.degrees(math.atan(t))
                    sum += rotate_angle
                    count += 1
                    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

        if count == 0:
            avg_rotate_angle = 0
        else:
            avg_rotate_angle = sum / count
        self.rotate_img = ndimage.rotate(img, avg_rotate_angle)

        self.rotate_theta = avg_rotate_angle
        self.count_rotate_vector()

    def count_rotate_vector(self):
        v1_new = (self.rotate_vector[0] * np.cos(self.rotate_theta / 180)) - \
                 (self.rotate_vector[1] * np.sin(self.rotate_theta / 180))
        v2_new = (self.rotate_vector[1] * np.cos(self.rotate_theta / 180)) + \
                 (self.rotate_vector[0] * np.sin(self.rotate_theta / 180))
        self.rotate_vector = np.array([v1_new, v2_new])

    def manual_set_rotate_vector(self, rotate_theta):
        self.rotate_theta = rotate_theta
        self.count_rotate_vector()

    def canny_threshold(self, img_path):
        img_original = cv2.imread(img_path)

        cv2.namedWindow('Canny')

        def nothing(x):
            pass

        cv2.createTrackbar('threshold1','Canny',50,400,nothing)
        cv2.createTrackbar('threshold2','Canny',100,400,nothing)
        while(1):

            threshold1=cv2.getTrackbarPos('threshold1','Canny')
            threshold2=cv2.getTrackbarPos('threshold2','Canny')

            img_edges=cv2.Canny(img_original,threshold1,threshold2)

            cv2.imshow('original',img_original)
            cv2.imshow('Canny',img_edges)
            if cv2.waitKey(1)==ord('q'):
                break
        cv2.destroyAllWindows()

if __name__ == '__main__':
    horizontal_correction = HorizontalCorrection()

    horizontal_correction.process(r'./test image/IMG_6386.JPG')
    print(horizontal_correction.rotate_theta)
    cv2.imwrite('./test result/1.png', horizontal_correction.rotate_img)
    cv2.imshow('rotate', horizontal_correction.rotate_img)
    cv2.waitKey()

Original: https://blog.csdn.net/weixin_42442319/article/details/124596103
Author: 橙橙小狸猫
Title: python 图片倾斜校正

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/518367/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球