ถ้าเราใช้โค้ดของเดิมแล้ว filter เลย เช่น ใช้ average filter เพื่อเบลอรูป ซึ่งใน PIL จะมีคำสั่งให้เช่น
kernel = [1]*25
img.filter(ImageFilter.Kernel((5,5),kernel))
ผลลัพธ์จะได้ประมาณนี้ (ให้สังเกตรอยต่อในแนวนอนในภาพ)
หมายเหตุ ข้อนี้ได้ลดขนาดของรูปเหลือ 256x256 เพื่อให้เห็นผลลัพธ์ชัดขึ้น
ซึ่งมาจากโค้ดต่อไปนี้
from PIL import Image, ImageTk, ImageFilter from Tkinter import Tk, Label img = Image.open("Lenna-gray-raw-256.tif") #create new output image out = Image.new(img.mode, img.size, None) #try to read every 64 rows rowRead = 64 #size of original image oriW, oriH = img.size totalRead = oriH/rowRead #image header size, please check by img.tile, it is different for images header = 8; #kernel size 5x5 ksize = 5 #loop for each partial read for rr in range(totalRead): #reopen image, necessary due to partial loading img = Image.open("Lenna-gray-raw-256.tif") #reading size eg. 256,64 img.size = (oriW, rowRead) #set tile size offset = rr*(rowRead*oriW) img.tile = [('raw', (0, 0, oriW, rowRead), header + offset, ('L', 0, 1))] #load part of image img.load() #filter part of image #create an average kernel of 5x5 = 25 elements kernel = [1]*(ksize*ksize) temp = img.filter(ImageFilter.Kernel((ksize,ksize),kernel)) #copy to new image #paste(source image, top-left corner) out.paste(temp,(0,rr*rowRead)) #display on Tkinter root = Tk() imgTk = ImageTk.PhotoImage(out) lbl = Label(root, image=imgTk) lbl.pack() root.mainloop()
จะเห็นว่ามีข้อผิดพลาดเกิดขึ้นเป็นแถบในแนวนอน ซึ่งก็คือรอยต่อระหว่างแต่ละรูปที่เราแบ่งส่วนในการโหลด
เพื่อที่จะแก้ปัญหาดังกล่าว อาจทำได้โดย อ่านภาพในแต่ละครั้ง ให้จำนวนแถวมากกว่าเดิมนิดนึง คือเพิ่มด้วยขนาดความสูงของ filter ที่จะใช้หารด้วยสอง เช่น
สมมติว่าแบ่งรูปออกเป็น 3 แถบ บน กลาง ล่าง
ถ้าอ่านทีละ 64 แถว และ filter มีขนาด 5x5
1. แถบบน จำนวนแถวที่อ่านใหม่ก็จะเป็น 64+(5-1)/2 = 64+2 = 66 แถว นั่นคือ เพิ่มล่างสองแถว
2. แถบกลาง จำนวนแถวที่อ่านใหม่ก็จะเป็น 64+4 = 68 แถว นั่นคือ เพิ่มบนสองแถว ล่างสองแถว
3. แถบล่าง 64 จำนวนแถวที่อ่านใหม่ก็จะเป็น 64+2 = 66 แถว นั่นคือ เพิ่มบนสองแถว
ซึ่งการกำหนดดังกล่างจะมีผลต่อค่า size และ tile ต้องกำหนดค่านี้ใหม่ T_T นอกจากนี้แล้ว ตอนประมวลผลเสร็จแต่ละแถบ ผลลัพธ์จะใช้เพียงแค่ 64 แถวเหมือนเดิม
ผลลัพธ์ใหม่คือ (สังเกตว่าไม่มีรอยต่อของแถบแล้ว)
โค้ดใหม่ก็จะประมาณนี้ครับ
from PIL import Image, ImageTk, ImageFilter from Tkinter import Tk, Label img = Image.open("Lenna-gray-raw-256.tif") #create new output image out = Image.new(img.mode, img.size, None) #try to read every 64 rows #total read = 256/64 = 4 rowRead = 64 #size of original image oriW, oriH = img.size totalRead = oriH/rowRead #image header size, please check by img.tile, it is different for images header = 8; #kernel size 5x5 ksize = 5 #loop for each partial read for rr in range(totalRead): #additional row to read at top of bottom extraTopRow = (ksize-1)/2 extraBottomRow = extraTopRow #if the first set of row if rr==0: extraTopRow = 0 elif rr==totalRead-1: #last set of row extraBottomRow = 0 #reopen image, necessary due to partial loading img = Image.open("Lenna-gray-raw-256.tif") #tile offset = rr*(rowRead*oriW) img.tile = [('raw', (0, 0 - extraTopRow, oriW, rowRead +extraTopRow +extraBottomRow), header + offset - (extraTopRow*oriW), ('L', 0, 1))] #set reading size img.size = (oriW, rowRead + extraTopRow + extraBottomRow) #load part of image img.load() #filter part of image #create an average kernel of 5x5 = 25 elements kernel = [1]*(ksize*ksize) temp = img.filter(ImageFilter.Kernel((ksize,ksize),kernel)) #crop to normal size #img.crop((x1,y1,x2,y2)) --> top left to bottom right crop = temp.crop((0,extraTopRow, oriW,extraTopRow+rowRead)) #copy to new image #paste(source image, top-left corner) out.paste(crop,(0,rr*rowRead)) #display on Tkinter root = Tk() imgTk = ImageTk.PhotoImage(out) lbl = Label(root, image=imgTk) lbl.pack() root.mainloop()
คำสั่ง ImageFilter.Kernel มีข้อจำกัดคือทำได้เฉพาะ kernel ขนาด 3x3 หรือ 5x5 เท่านั้นครับ
No comments:
Post a Comment