因爲之前寫這個實驗的時候,組織上有很多事情,所以當時,隨便網上找了個 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型形變
圖片旋轉
圖片平移