上次寫了圖像變換-旋轉問題,試一試?,後面留了個問題,本來就是随便說說的,留給大家一個探索的機會,剛好碰到最近事情也有點多,沒空弄。
不過随着和有點意思同學在背景的不斷留言交流,發現留了好多坑了,趕緊抽個時間,先填上一個再說。
下面開始正文。
下面有一個矩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倍。
而平移用的是矩陣加法,不通用,通過齊次坐标,下面兩個結果是一樣的,加法變成了乘法。