天天看點

圖像變換-旋轉問題來了

上次寫了圖像變換-旋轉問題,試一試?,後面留了個問題,本來就是随便說說的,留給大家一個探索的機會,剛好碰到最近事情也有點多,沒空弄。

不過随着和有點意思同學在背景的不斷留言交流,發現留了好多坑了,趕緊抽個時間,先填上一個再說。

下面開始正文。

下面有一個矩3*3的矩陣(你也可以看做二維清單)。

[[1 2 3]
 [4 5 6]
 [7 8 9]]      

問題1:順時針旋轉90度,得到以下矩陣。

[[7 4 1]
 [8 5 2]
 [9 6 3]]      

參考:

import numpy as np
a = np.array(np.arange(1,10)).reshape(3,3)
print(a)
n = len(a)
b = a.copy()
for i in range(n):
     for j in range(n):
         b[i][j] = a[n-1-j][i] # 順時針旋轉90
         # b[i][j] = a[j][n - 1 - i] # 逆時針旋轉90
print(b)      
圖像變換-旋轉問題來了

​說明:​這裡的解法比較好了解,但是雙重循環複雜度比較高,看了網上的解法,有四種,感興趣的可以自己搜尋。

問題2:對矩陣進行鏡像操作

[[3 2 1]
 [6 5 4]
 [9 8 7]]      

參考:

import numpy as np
a = np.array(np.arange(1,10)).reshape(3,3)
print(a)
b = a[:,::-1]
print(b)      
圖像變換-旋轉問題來了

問題3:上下翻轉操作。

[[7 8 9]
 [4 5 6]
 [1 2 3]]      

參考:

import numpy as np


a = np.array(np.arange(1,10)).reshape(3,3)
print(a)
b = a[::-1] # 上下翻轉
print(b)      
圖像變換-旋轉問題來了

上面僅僅是以數字作為測試,真實圖檔,隻需将a替換成圖像矩陣即可,其餘不變。

from PIL import Image
import numpy as np
img = Image.open("cat.png")
a = np.asarray(img)
...      

上面的圖像變換相對來說比較簡單,主要就是像素的位置替換了一下。

不過除了上面的,還有一些其它的圖像變換,比如圖像縮放(放大、縮小),其它角度旋轉、平移等各種操作;

這類幾何變換,相對于前面提到的變換,盡管還是改同樣變了原圖像像素點在新圖像中的空間位置,但是也引入了一些新的問題。

平移

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
# 平移
def move(image, delta_x,delta_y):
    rows,cols = image.shape[:2]
    empty_image = np.zeros(image.shape,dtype=np.uint8)
    transform=np.array([delta_x,delta_y])
    for row in range(rows):
        for col in range(cols):
            x1,y1 = np.array([row,col])+transform
            if x1<rows and x1>=0 and y1<cols and y1 >=0:
                empty_image[x1][y1]=image[row][col]
    return empty_image
img = Image.open("cat.png")
image = np.asarray(img)
image = move(image,50,250)
plt.imshow(image)
plt.show()      

平移比較簡單,主要就是矩陣的加法,超出部分删除。

圖像變換-旋轉問題來了
圖像變換-旋轉問題來了
圖像變換-旋轉問題來了

旋轉

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image


def rotate(image,angle):
    cos = np.math.cos(np.math.radians(angle))
    sin = np.math.sin(np.math.radians(angle))
    transform = np.array([[cos, -sin],
                  [sin, cos]])
    rows, cols = image.shape[:2]
    empty_image = np.zeros(image.shape, dtype=np.uint8)
    for row in range(rows):
        for col in range(cols):
             # 計算旋轉後的坐标
             x1,y1 = transform.dot(np.array([row,col]))
             # 隻計算範圍之内的
             if x1 < rows and x1 >= 0 and y1 < cols and y1 >= 0:
                 # 通過原圖像的坐标計算旋轉之後的坐标,并将相應的灰階值傳給旋轉後的圖像
                 empty_image[int(x1)][int(y1)] = image[row][col]


    return empty_image
    
img = Image.open("cat.png")
image = np.asarray(img)
image = rotate(image,-30)
plt.imshow(image)
plt.show()      

旋轉可以看做圖檔上的每個點旋轉。

圖像變換-旋轉問題來了
圖像變換-旋轉問題來了

換算後得到下面的公式。

圖像變換-旋轉問題來了
圖像變換-旋轉問題來了

這裡是以圖檔左上角旋轉的,超出邊界部分删除了。得到的結果出現了一些有規律的噪聲,之是以出現這樣的問題,是因為通過原圖像的坐标計算旋轉之後的坐标,并将相應的灰階值傳給旋轉後的圖像。得到的坐标有些是小數,進行了取整操作,這樣部分像素并沒有對應的像素值。

要實作下面這種效果,首先需要以圖像的中心作為中心點,然後采取後向映射的方法——即從旋轉後的圖像出發,找到對應的原圖像的點,然後将原圖像中的灰階值傳遞過來即可,這樣旋轉後的圖像的每個像素肯定可以對應到原圖像中的一個點。

圖像變換-旋轉問題來了

具體實作方式可參考這兩篇文章,都是一些數學運算,講的比較清楚了:

https://www.jianshu.com/p/56a717173227

如果需要多次變換(縮放,旋轉,平移),需要引入齊次坐标(在微信讀書數字圖像處理上看到的),通過齊次坐标,不管怎樣變換,變換多少次,都可以表示成一連串的矩陣相乘了。

例如先放大2倍,然後旋轉45度,然後再縮小0.5倍。

圖像變換-旋轉問題來了

而平移用的是矩陣加法,不通用,通過齊次坐标,下面兩個結果是一樣的,加法變成了乘法。

圖像變換-旋轉問題來了
圖像變換-旋轉問題來了

繼續閱讀