1. 程式人生 > >影象處理二:仿射變換和透視變換

影象處理二:仿射變換和透視變換

一、仿射變換(Affine Transformation)

        放射變換(平面變換、二維座標變換):是空間直角座標系的變換,從一個二維座標變換到另一個二維座標,仿射變換是一個線性變換,保持了影象的“平行性”和“平直性”,即影象中原來的直線和平行線,變換後仍然保持原來的直線和平行線。

       仿射變換比較常用的特殊變換有平移(Translation)、縮放(Scale)、翻轉(Flip)、旋轉(Rotation)和剪下(Shear);

        仿射變換性質:

(1)仿射變化只有6個自由度(對應變換中的6個係數),仿射變換後相互平行直線仍然是平行直線,三角形對映後仍是三角形;但卻不能保證四邊形以上的多變性對映為等邊數的多邊形;

(2)仿射變換的乘積和逆變換仍是仿射變換;

(3)仿射變換包含:平移、旋轉、縮放等幾何變換。

二、透視變換(Perspective Transformation)

       透視變換(空間變換、三維座標變換):是指利用透視中心、像點、目標點三點共線的條件,按透視旋轉定律使承影面(透視面)繞跡線(透視軸)旋轉某一角度,破壞原有的投影光線束,仍能保持承影面上投影幾何圖形不變的變換。

三、原始碼

影象若需儲存程式碼為:

cv2.imwrite("F:/b.jpg",res)

第一個引數:路徑下,指定檔名;

第二個引數:儲存的影象。 

1. 平移

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('F:/a.jpg')
H = np.float32([[1,0,100],[0,1,100]])
rows,cols = img.shape[:2]
res = cv2.warpAffine(img,H,(rows,cols)) #需要影象、變換矩陣、變換後的大小
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(res)

2. 放縮

      resize()函式可以進行影象的放大、縮小,但需要選擇合適的插值方式。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('F:/a.jpg')
res1 = cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
height,width = img.shape[:2]
res2 = cv2.resize(img,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
plt.subplot(131)
plt.imshow(img)
plt.subplot(132)
plt.imshow(res1)
plt.subplot(133)
plt.imshow(res2)

 

3. 旋轉

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('F:/a.jpg')
rows,cols = img.shape[:2]
#第一個引數旋轉中心,第二個引數旋轉角度,第三個引數:縮放比例
M = cv2.getRotationMatrix2D((cols/2,rows/2),45,1)
#第三個引數:變換後的影象大小
res = cv2.warpAffine(img,M,(rows,cols))

plt.subplot(121)
plt.imshow(img)
plt.subplot(122)
plt.imshow(res)

 

4. 仿射

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('F:/a.jpg')
rows,cols = img.shape[:2]
pts1 = np.float32([[50,50],[200,50],[50,200]])
pts2 = np.float32([[10,100],[200,50],[100,250]])
M = cv2.getAffineTransform(pts1,pts2)
#第三個引數:變換後的影象大小
res = cv2.warpAffine(img,M,(rows,cols))
plt.subplot(121)
plt.imshow(img)
plt.subplot(122)

5. 投影

(1)垂直投影

import cv2  
import numpy as np  
from matplotlib import pyplot as plt
  
img=cv2.imread('F:/a.jpg')
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   #將BGR圖轉為灰度圖
ret,thresh1=cv2.threshold(GrayImage,130,255,cv2.THRESH_BINARY)  #將圖片進行二值化(130,255)之間的點均變為255(背景)
(h,w)=thresh1.shape #返回高和寬
a = [0 for z in range(0, w)]  
#記錄每一列的波峰
for j in range(0,w): #遍歷一列 
    for i in range(0,h):  #遍歷一行
        if  thresh1[i,j]==0:  #如果改點為黑點
            a[j]+=1  		#該列的計數器加一計數
            thresh1[i,j]=255  #記錄完後將其變為白色          
for j  in range(0,w):  #遍歷每一列
    for i in range((h-a[j]),h):  #從該列應該變黑的最頂部的點開始向最底部塗黑
        thresh1[i,j]=0   #塗黑
plt.imshow(thresh1,cmap=plt.gray())
plt.show()
cv2.imshow('img',thresh1)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

(2)水平投影

import cv2  
import numpy as np  
from matplotlib import pyplot as plt
  
img=cv2.imread('F:/a.jpg') 
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
ret,thresh1=cv2.threshold(GrayImage,130,255,cv2.THRESH_BINARY)
 
(h,w)=thresh1.shape #返回高和寬
 
a = [0 for z in range(0, h)] 
 
for j in range(0,h):  
    for i in range(0,w):  
        if  thresh1[j,i]==0: 
            a[j]+=1 
            thresh1[j,i]=255
         
for j  in range(0,h):  
    for i in range(0,a[j]):   
        thresh1[j,i]=0    
 
plt.imshow(thresh1,cmap=plt.gray())

(3)基於投影的字元分割

import cv2
import numpy as np

path = 'F:/b.jpg'
root = 'F:/b/'
dsize = 28
img = cv2.imread(path)
data = np.array(img)
len_x = data.shape[0] 
len_y = data.shape[1]
min_val = 10 #設定最小的文字畫素高度

start_i = -1
end_i = -1
rowPairs = [] #存放每行的起止座標

#行分割
for i in range(len_x):
    if(not data[i].all() and start_i < 0): 
        start_i = i
    elif(not data[i].all()):
        end_i = i
    elif (data[i].all() and start_i >= 0):
        #print(end_i - start_i)
        if(end_i - start_i >= min_val):
            rowPairs.append((start_i, end_i))
        start_i, end_i = -1, -1
#列分割
start_j = -1
end_j = -1
min_val_word = 8  #最小文字畫素長度
number = 0 #分割後儲存編號
for start, end in rowPairs:
    for j in range(len_y):
        if(not data[start: end, j].all() and start_j < 0):
            start_j = j
        elif(not data[start: end, j].all()):
             end_j = j
        elif(data[start: end, j].all() and start_j >= 0):
            if(end_j - start_j >= min_val_word):
                #print(end_j - start_j)
                tmp = data[start:end, start_j: end_j]
                im2save = cv2.resize(tmp, (dsize,dsize)) #歸一化處理
                cv2.imwrite(root + '%d.png' % number, im2save) 
                number += 1
                #print("%d  pic" % number)
            start_j, end_j = -1, -1