- 推薦自己的專欄:分享一些Python案例,將所學用出來
- 使用Python第三方圖像處理庫Pillow處理圖像時,通常是調用模塊中提供的函數和對象來處理圖像的基本處理
圖像的數據結構基礎
一:在“底層”圖像是由像素點組成的二維數,每個像素點的位置表示爲兩個整數的元組
二:像素的值根據圖像模式由對應的元組組成(例如,RGB模式表示爲三個整數值組成的元組,分別表示構成顏色的紅、綠、藍的值,範圍從0到255)
PIL.Image模塊中的Image類的方法:
- getpixel(loc) 返回位於位置loc的像素的顏色
- putpixel(loc, pix) 把位於位置loc的顏色替換爲pix
拷貝圖像
拷貝圖像的算法可以通過打開原始圖像,創建一個新的大小相同的空白圖像,然後將舊圖像中的像素顏色複製到新圖像相應的像素中。
即使用嵌套循環,把舊圖像位置 (i, j) 的像素複製到新圖像的位置 (i, j)
我的電腦,D:\zgh\picture
這個路徑下有一個圖片zgh.png
import PIL.Image
def copy(im):
im_new = PIL.Image.new(im.mode, im.size)
width, height = im.size
for i in range(0, width):
for j in range(0, height):
pix = im.getpixel((i, j))
im_new.putpixel((i, j), pix)
return im_new
if __name__ == '__main__':
im = PIL.Image.open("D:\zgh\picture\zgh.png")
copy(im).show()
運行之後,會出現一個圖像文件,顯示的圖像與上圖一樣
- im.size返回包含圖像寬度和高度的元組,單位爲像素
- im.mode返回包含圖像模式的字符串(RGB、CYMK、Grayscale…)
剪裁圖像
剪裁圖像的算法可以通過打開原始圖像,指定一個四元組的剪裁框,創建一個與剪裁框大小相同的空白圖像,然後將舊圖像中剪裁框內的像素顏色複製到新圖像中。同樣可以實用嵌套循環實現像素複製
原圖像:
其分辨率爲959 × 959
import PIL.Image
def crop(im, box):
x1, y1, x2, y2 = box
width, height = x2-x1, y2-y1
im_new = PIL.Image.new(im.mode, (width, height))
for i in range(0, width):
for j in range(0, height):
pix = im.getpixel((x1+i, y1+j))
im_new.putpixel((i, j), pix)
return im_new
if __name__ == '__main__':
box = (400, 400, 800, 800)
im = PIL.Image.open("D:\zgh\picture\zgh.png")
crop(im, box).show()
我圖像對圖像的剪裁框,左上角座標爲(400, 400),右下角爲(800, 800)
box = (400, 400, 800, 800)
運行後,顯示剪裁圖像:
水平或垂直翻轉圖像
水平或垂直翻轉的算法可以通過打開原始圖像,創建一個新的大小相同的空白圖像,然後講舊圖像複製到新圖像對應的像素中
- 水平翻轉時:原始圖像的的像素(i, j)映射到目標圖像的位置(width-i-1, j)
- 垂直翻轉時:原始圖像的的像素(i, j)映射到目標圖像的位置(i, height-j-1)
原圖像:
import PIL.Image
def flip(im, orient='H'):
width, height = im.size
im_new = PIL.Image.new(im.mode, im.size)
for i in range(0, width):
for j in range(0, height):
pix = im.getpixel((i, j))
if orient == 'H':
im_new.putpixel((width-1-i, j), pix)
else:
im_new.putpixel((i, height-1-j), pix)
return im_new
if __name__ == '__main__':
im = PIL.Image.open("D:\zgh\picture\zgh.png")
flip(im, 'H').show()
flip(im, 'V').show()
語義化的取名:
- H 即horizon,水平線
- V 即vertical,垂直線
水平翻轉:
垂直翻轉:
逆時針或順時針旋轉圖像90度
逆時針或順時針旋轉圖像90度的算法可以通過打開原始圖像,創建一個新的大小相同的空白圖像,然後講舊圖像複製到新圖像對應的像素中
- 逆時針旋轉圖像90度:原始圖像的的像素(i, j)映射到目標圖像的位置(j, width-i-1)
- 順時針旋轉圖像90度:原始圖像的的像素(i, j)映射到目標圖像的位置(height-j-1, i)
原圖像:
import PIL.Image
def rotate(im, orient='CCW'):
width, height = im.size
im_new = PIL.Image.new(im.mode, im.size)
for i in range(0, width):
for j in range(0, height):
pix = im.getpixel((i, j))
if orient == 'CCW':
im_new.putpixel((j, width-1-i), pix)
else:
im_new.putpixel((height-1-j, i), pix)
return im_new
if __name__ == '__main__':
im = PIL.Image.open("D:\zgh\picture\zgh.png")
rotate(im, 'CCW').show()
rotate(im, 'CW').show()
語義化的取名:
- CCW,即Counter clockwise rotation逆時針旋轉
- CW,即Clockwise rotation順時針旋轉
逆時針旋轉圖像90度:
順時針旋轉圖像90度:
平滑圖像過濾器
圖像過濾器是原始圖像中靠近位置(i, j)的多個像素顏色以某種方式組合運算形成新的圖像對象
例如,簡單的平滑過濾器算法可以通過打開原始圖像,創建一個新的大小相同的空白圖像,然後將新圖像中的每個像素(i, j)的顏色設置爲原始像素(i, j)及其相鄰像素的顏色的平均值。
- 不位於圖像邊界上像素(i, j)有8個相鄰像素,其相鄰像素位於從列 i-1 到 列 i+1,和行 j-1 到 行 j+1 範圍
- 位於圖像邊界上像素(i, j)
需要特殊處理,我偷個懶,因爲邊界上的點相對於圖像佔比特別小,我就讓邊界點上的像素不變了
原圖像:
代碼一(跟個傻憨憨一樣,寫的繁瑣,且容易出錯):
import PIL.Image
def smooth(im):
width, height = im.size
im_new = PIL.Image.new(im.mode, im.size)
for i in range(0, width):
for j in range(0, height):
if i > 0 and i < width-1 and j > 0 and j < height-1:
pix_R = int((im.getpixel((i, j))[0] + im.getpixel((i-1, j))[0] + im.getpixel((i+1, j))[0] + im.getpixel((i, j-1))[0] + im.getpixel((i, j+1))[0] + im.getpixel((i-1, j-1))[0] + im.getpixel((i-1, j+1))[0] + im.getpixel((i+1, j-1))[0] + im.getpixel((i+1, j+1))[0]) / 9)
pix_G = int((im.getpixel((i, j))[1] + im.getpixel((i-1, j))[1] + im.getpixel((i+1, j))[1] + im.getpixel((i, j-1))[1] + im.getpixel((i, j+1))[1] + im.getpixel((i-1, j-1))[1] + im.getpixel((i-1, j+1))[1] + im.getpixel((i+1, j-1))[1] + im.getpixel((i+1, j+1))[1]) / 9)
pix_B = int((im.getpixel((i, j))[2] + im.getpixel((i-1, j))[2] + im.getpixel((i+1, j))[2] + im.getpixel((i, j-1))[2] + im.getpixel((i, j+1))[2] + im.getpixel((i-1, j-1))[2] + im.getpixel((i-1, j+1))[2] + im.getpixel((i+1, j-1))[2] + im.getpixel((i+1, j+1))[2]) / 9)
pix = (pix_R, pix_G, pix_B)
else:
pix = im.getpixel((i, j))
im_new.putpixel((i, j), pix)
return im_new
if __name__ == '__main__':
im = PIL.Image.open("D:\zgh\picture\zgh.png")
smooth(im).show()
代碼二(代碼簡潔明瞭):
import PIL.Image
import numpy
def smooth(im):
width, height = im.size
im_new = PIL.Image.new(im.mode, im.size)
for i in range(1, width-1):
for j in range(1, height-1):
pix_R = 0; pix_G = 0; pix_B = 0
for x in range(-1, 2):
for y in range(-1, 2):
pix_R += im.getpixel((i+x, j+y))[0] / 9
pix_G += im.getpixel((i+x, j+y))[1] / 9
pix_B += im.getpixel((i+x, j+y))[2] / 9
im_new.putpixel((i, j), (int(pix_R), int(pix_G), int(pix_B)))
return im_new
if __name__ == '__main__':
im = PIL.Image.open("D:\zgh\picture\zgh.png")
smooth(im).show()
可惜水平有限,我寫的平滑圖像處理器的代碼性能不高,運行需要一定時間,我的電腦至少需要15秒
平滑圖像過濾後:
個人感覺沒啥子變化…