(自己编写函数)Python + Opencv 图像几何变换(缩小、放大、内凹,外凸,梯形变形、三角型变形、S型变形、图片旋转、图片平移)

因为之前写这个实验的时候,组织上有很多事情,所以当时,随便网上找了个 C++ 的上交了,昨天就补写了一下。这里写的缩小和方法都是等比例进行的,不是等比例的改也比较简单,这里就不改了,有兴趣的朋友可以自己尝试着改改,另外这里用的是灰度图,彩色图稍微改改就行了

比例缩小

ratio 是缩小比例,大致思路是:

1、先根据你输入的缩放比例生成一个与原图 * 缩放比例相同大小的灰度级矩阵。

2、根据书中说的首先根据缩小的倍率去算出,在原图中要隔多少个点采集一次生成新的图像,这就是我里面写的步长。比如:4*4 的 图像要缩小0.5倍,那么步长就是2 除了第一个点之外,其他每个点都要每隔两个点 取一次。

#按比例缩小
def DOWNRESIZE(gray , ratio=0.8) :
    height , width = gray.shape[0] , gray.shape[1]
    resize_width , resize_height = int(width * ratio) , int(height * ratio)
    resize_gray = np.zeros([resize_height,resize_width],np.uint8)   #创建一个和原图像 *缩小比例相同像素的空图
    stepsize = 1.0/ratio    #原图像的采集步长
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            if i  == 0 and j == 0 :     #缩小图(0,0)地方的像素用原图(1,1)的地方代替
                resize_gray[i][j] = gray[1][1]
            else :      #缩小图其他地方的像素用此时原图对应的坐标-1的地方代替
                resize_gray[i][j] = gray[int(i*stepsize)-1][int(j*stepsize)-1]
    cv2.imshow("old",gray)
    cv2.imshow("Downresize",resize_gray)
    cv2.waitKey(0)

比例放大

比例方法,这里使用了两种方法:①最邻近插值法;②双线性插值。完全是根据概念,写的算法,概念就不重复了,可以百度,网上很多。

#按比例放大
def UPSIZE(gray , ratio=1.2) :
    height , width = gray.shape[0] , gray.shape[1]
    resize_width , resize_height = int(width * ratio) , int(height * ratio)
    resize_gray = np.zeros([resize_height,resize_width],np.uint8)
    """
    #最邻近插值法
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            if i  == 0 and j == 0 :
                resize_gray[i][j] = gray[int(i/ratio)+1][int(j/ratio)+1]
            else :
                resize_gray[i][j] = gray[int(i/ratio)-1][int(j/ratio)-1]
    """
    #双线性插值
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            x = i/ratio
            y = j/ratio
            p=(i+0.0)/ratio-x
            q=(j+0.0)/ratio-y
            x=int(x)-1
            y=int(y)-1
            if x+1<i and y+1<j:
                resize_gray[i,j]=int(gray[x,y]*(1-p)*(1-q)+gray[x,y+1]*q*(1-p)+gray[x+1,y]*(1-q)*p+gray[x+1,y+1]*p*q)
    cv2.imshow("old",gray)
    cv2.imshow("Upresize",resize_gray)
    cv2.waitKey(0)

水平内凹

内凹与外凸还有S型都差不多,大致思路,生成正弦波的波形,然后,从这个正弦波去确定那些地方是黑色的,最后根据每行中不是黑色的部分和原来的比重,根据之前的缩小的步长去进行每行的缩放即可。

#水平内凹
def CONCAVE(gray) :
    RANGE = 400
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width- RANGE) * math.sin(((2 * math.pi * i) / height) / 2))
        for j in range (int(temp+0.5),int(width-temp)) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Concave", resize_gray)
    cv2.waitKey(0)

水平外凸

#水平外凸
def CONVEX(gray) :
    RANGE = 400
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    temp1 = []
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width- RANGE) * math.sin(((2 * math.pi * i) / height) / 2))
        temp = 200 - temp
        for j in range (int(temp+0.5),int(width-temp)) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Convex", resize_gray)
    cv2.waitKey(0)

梯形形变

#梯形形变
def TRAPEZOID(gray,k=0.3) :
    height, width = gray.shape[0], gray.shape[1]
    value = k*height
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        temp = int( value - k * i ) 
        for j in range (temp,width-temp) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Trapezoid", resize_gray)
    cv2.waitKey(0)

三角形形变

#三角形形变
def TRIANGLE(gray,k=0.5) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        temp = int( k * i ) 
        for j in range (temp) :
            #每行非黑色区域的长度
            distance = temp
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Triangle", resize_gray)
    cv2.waitKey(0)

S形形变

#S形变
def SSHAPE(gray,RANGE=450) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width - RANGE) / 2 + (width- RANGE) * math.sin((2 * math.pi * i) / height + math.pi) / 2)
        for j in range (int(temp+0.5),int(RANGE+temp)) :
            #映射关系
            m = int(((j-temp) * width / RANGE))
            if m >= width :
                m=width-1
            if m < 0 :
                m=0
            resize_gray[i,j]=gray[i,m]

    cv2.imshow("old", gray)
    cv2.imshow("Sshape", resize_gray)
    cv2.waitKey(0)

图片旋转

#图片旋转
def ROTATE(gray, ANGLE = 45,center=None, scale=1.0) :
    #将角度转化为弧度
    """ #特别神奇的图案
    ANGLE =  math.radians(ANGLE)
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([800,800], np.uint8)
    for i in range (height) :
        for j in range (width) :
            angle = math.asin( i / width )
            ANGLE = angle + ANGLE
            x,y = int(width * math.cos(ANGLE)) , int(width * math.sin(ANGLE))
            resize_gray[x][y] = gray[i][j]
    cv2.imshow("old", gray)
    cv2.imshow("Rotate", resize_gray)
    cv2.waitKey(0)
    """
    (height, width) = gray.shape[:2]
    (cX, cY) = (width // 2, height // 2)
 
    M = cv2.getRotationMatrix2D((cX, cY), -ANGLE, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
 
    nW = int((height * sin) + (width * cos))
    nH = int((height * cos) + (width * sin))
 
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY
 
    shuchu=cv2.warpAffine(gray, M, (nW, nH))

    cv2.imshow("old", gray)
    cv2.imshow("Rotate", shuchu)
    cv2.waitKey(0)

图像平移

平移很简单,就不多说了

#图片平移
def HORIZONTALMOVE(gray,move_x,move_y) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        for j in range (width) :
            if i + move_x < height and j + move_y < width :
                resize_gray[i][j] = gray[i+move_x][j+move_y]
            else :
                resize_gray [i][j] = 0
    cv2.imshow("old", gray)
    cv2.imshow("Horizeontalmove", resize_gray)
    cv2.waitKey(0)

主函数

def MAIN() :
    image = cv2.imread(r"D:\Code\Python\2.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    while True :
        print("0: 按比例缩小\n1: 按比例放大\n2: 水平外凹\n3: 水平外凸\n4: 梯形变形\n5: 三角形变形\n6: S形变形\n7: 图片旋转\n8: 图片平移\n")
        keyinput = input ("请输入数字0—8,选择你需要的变换(按'Q'或'q'退出):\n")
        if keyinput == "0" :
            ratio = float(input("请输入缩小倍数:\n"))
            DOWNRESIZE(gray , ratio)
            continue
        elif keyinput == "1" :
            ratio = float(input("请输入放大倍数:\n"))
            UPSIZE(gray , ratio)
            continue
        elif keyinput == "2" :
            CONCAVE(gray)
            continue
        elif keyinput == "3" :
            CONVEX(gray)
            continue
        elif keyinput == "4" :
            k = float(input("请输入梯形的斜度:\n"))
            TRAPEZOID(gray,k)
            continue
        elif keyinput == "5" :
            k = float(input("请输入三角形的斜度:\n"))
            TRIANGLE(gray,k)
            continue
        elif keyinput == "6" :
            RANGE = float(input("请输入变换强度:\n"))
            SSHAPE(gray,RANGE)
            continue
        elif keyinput == "7" :
            ANGLE = float(input("请输入旋转角度:\n"))
            ROTATE(gray,ANGLE)
            continue
        elif keyinput == "8" :
            move_x = int(input("请输入x轴偏移值:\n"))
            move_y = int(input("请输入y轴偏移值:\n"))
            HORIZONTALMOVE(gray,move_x,move_y)
            continue
        elif keyinput == "Q" or "q" :
            break
        else :
            keyinput = input("您输入的字符有误,请输入 0-8 之间的数字:")

完整代码以及展示

import matplotlib.pyplot as plt
from scipy import signal
import numpy as np
import copy as cp
import random
import math
import cv2
import collections

#按比例缩小
def DOWNRESIZE(gray , ratio=0.8) :
    height , width = gray.shape[0] , gray.shape[1]
    resize_width , resize_height = int(width * ratio) , int(height * ratio)
    resize_gray = np.zeros([resize_height,resize_width],np.uint8)   #创建一个和原图像 *缩小比例相同像素的空图
    stepsize = 1.0/ratio    #原图像的采集步长
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            if i  == 0 and j == 0 :     #缩小图(0,0)地方的像素用原图(1,1)的地方代替
                resize_gray[i][j] = gray[1][1]
            else :      #缩小图其他地方的像素用此时原图对应的坐标-1的地方代替
                resize_gray[i][j] = gray[int(i*stepsize)-1][int(j*stepsize)-1]
    cv2.imshow("old",gray)
    cv2.imshow("Downresize",resize_gray)
    cv2.waitKey(0)


#按比例放大
def UPSIZE(gray , ratio=1.2) :
    height , width = gray.shape[0] , gray.shape[1]
    resize_width , resize_height = int(width * ratio) , int(height * ratio)
    resize_gray = np.zeros([resize_height,resize_width],np.uint8)
    """
    #最邻近插值法
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            if i  == 0 and j == 0 :
                resize_gray[i][j] = gray[int(i/ratio)+1][int(j/ratio)+1]
            else :
                resize_gray[i][j] = gray[int(i/ratio)-1][int(j/ratio)-1]
    """
    #双线性插值
    for i in range (0,resize_height) :
        for j in range (0,resize_width) :
            x = i/ratio
            y = j/ratio
            p=(i+0.0)/ratio-x
            q=(j+0.0)/ratio-y
            x=int(x)-1
            y=int(y)-1
            if x+1<i and y+1<j:
                resize_gray[i,j]=int(gray[x,y]*(1-p)*(1-q)+gray[x,y+1]*q*(1-p)+gray[x+1,y]*(1-q)*p+gray[x+1,y+1]*p*q)
    cv2.imshow("old",gray)
    cv2.imshow("Upresize",resize_gray)
    cv2.waitKey(0)

#水平内凹
def CONCAVE(gray) :
    RANGE = 400
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width- RANGE) * math.sin(((2 * math.pi * i) / height) / 2))
        for j in range (int(temp+0.5),int(width-temp)) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Concave", resize_gray)
    cv2.waitKey(0)


#水平外凸
def CONVEX(gray) :
    RANGE = 400
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    temp1 = []
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width- RANGE) * math.sin(((2 * math.pi * i) / height) / 2))
        temp = 200 - temp
        for j in range (int(temp+0.5),int(width-temp)) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Convex", resize_gray)
    cv2.waitKey(0)

#梯形形变
def TRAPEZOID(gray,k=0.3) :
    height, width = gray.shape[0], gray.shape[1]
    value = k*height
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        temp = int( value - k * i ) 
        for j in range (temp,width-temp) :
            #每行非黑色区域的长度
            distance = int(width-temp) - int(temp+0.5)
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Trapezoid", resize_gray)
    cv2.waitKey(0)

#三角形形变
def TRIANGLE(gray,k=0.5) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        temp = int( k * i ) 
        for j in range (temp) :
            #每行非黑色区域的长度
            distance = temp
            #缩小的倍率
            ratio = distance / width
            #取点的步长
            stepsize = 1.0/ratio
            #将同意行缩小相同倍率
            resize_gray[i][j] = gray[i][int((j-temp)*stepsize)]
    cv2.imshow("old", gray)
    cv2.imshow("Triangle", resize_gray)
    cv2.waitKey(0)

#S形变
def SSHAPE(gray,RANGE=450) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range(height):
        # 得到正弦波的波形,即j对应的起点
        temp = float((width - RANGE) / 2 + (width- RANGE) * math.sin((2 * math.pi * i) / height + math.pi) / 2)
        for j in range (int(temp+0.5),int(RANGE+temp)) :
            #映射关系
            m = int(((j-temp) * width / RANGE))
            if m >= width :
                m=width-1
            if m < 0 :
                m=0
            resize_gray[i,j]=gray[i,m]

    cv2.imshow("old", gray)
    cv2.imshow("Sshape", resize_gray)
    cv2.waitKey(0)

#图片旋转
def ROTATE(gray, ANGLE = 45,center=None, scale=1.0) :
    #将角度转化为弧度
    """ #特别神奇的图案
    ANGLE =  math.radians(ANGLE)
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([800,800], np.uint8)
    for i in range (height) :
        for j in range (width) :
            angle = math.asin( i / width )
            ANGLE = angle + ANGLE
            x,y = int(width * math.cos(ANGLE)) , int(width * math.sin(ANGLE))
            resize_gray[x][y] = gray[i][j]
    cv2.imshow("old", gray)
    cv2.imshow("Rotate", resize_gray)
    cv2.waitKey(0)
    """
    (height, width) = gray.shape[:2]
    (cX, cY) = (width // 2, height // 2)
 
    M = cv2.getRotationMatrix2D((cX, cY), -ANGLE, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
 
    nW = int((height * sin) + (width * cos))
    nH = int((height * cos) + (width * sin))
 
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY
 
    shuchu=cv2.warpAffine(gray, M, (nW, nH))

    cv2.imshow("old", gray)
    cv2.imshow("Rotate", shuchu)
    cv2.waitKey(0)

#图片平移
def HORIZONTALMOVE(gray,move_x,move_y) :
    height, width = gray.shape[0], gray.shape[1]
    resize_gray = np.zeros([height, width], np.uint8)
    for i in range (height) :
        for j in range (width) :
            if i + move_x < height and j + move_y < width :
                resize_gray[i][j] = gray[i+move_x][j+move_y]
            else :
                resize_gray [i][j] = 0
    cv2.imshow("old", gray)
    cv2.imshow("Horizeontalmove", resize_gray)
    cv2.waitKey(0)

def MAIN() :
    image = cv2.imread(r"D:\Code\Python\2.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    while True :
        print("0: 按比例缩小\n1: 按比例放大\n2: 水平外凹\n3: 水平外凸\n4: 梯形变形\n5: 三角形变形\n6: S形变形\n7: 图片旋转\n8: 图片平移\n")
        keyinput = input ("请输入数字0—8,选择你需要的变换(按'Q'或'q'退出):\n")
        if keyinput == "0" :
            ratio = float(input("请输入缩小倍数:\n"))
            DOWNRESIZE(gray , ratio)
            continue
        elif keyinput == "1" :
            ratio = float(input("请输入放大倍数:\n"))
            UPSIZE(gray , ratio)
            continue
        elif keyinput == "2" :
            CONCAVE(gray)
            continue
        elif keyinput == "3" :
            CONVEX(gray)
            continue
        elif keyinput == "4" :
            k = float(input("请输入梯形的斜度:\n"))
            TRAPEZOID(gray,k)
            continue
        elif keyinput == "5" :
            k = float(input("请输入三角形的斜度:\n"))
            TRIANGLE(gray,k)
            continue
        elif keyinput == "6" :
            RANGE = float(input("请输入变换强度:\n"))
            SSHAPE(gray,RANGE)
            continue
        elif keyinput == "7" :
            ANGLE = float(input("请输入旋转角度:\n"))
            ROTATE(gray,ANGLE)
            continue
        elif keyinput == "8" :
            move_x = int(input("请输入x轴偏移值:\n"))
            move_y = int(input("请输入y轴偏移值:\n"))
            HORIZONTALMOVE(gray,move_x,move_y)
            continue
        elif keyinput == "Q" or "q" :
            break
        else :
            keyinput = input("您输入的字符有误,请输入 0-8 之间的数字:")

 
if __name__ == "__main__":
    MAIN()

变换结果

缩小

在这里插入图片描述

放大

在这里插入图片描述

水平内凹

水平外凸

梯形形变

在这里插入图片描述

三角形形变

在这里插入图片描述

S型形变

在这里插入图片描述

图片旋转

在这里插入图片描述

图片平移

(自己编写函数)Python + Opencv 图像几何变换(缩小、放大、内凹,外凸,梯形变形、三角型变形、S型变形、图片旋转、图片平移)_第1张图片

你可能感兴趣的:(python,OpenCV)