Tuesday, December 9, 2014

การอ่านภาพขนาดใหญ่ทีละส่วน ด้วย Python และ PIL ตอนที่ 3

ต่อจากคราวที่แล้ว เราได้ลองอ่านส่วนหนึ่งของภาพขึ้นมาจำนวน 64 แถว

ตอนนี้เราจะลองใช้ลูปอ่านค่าจนครบรูป

ทบทวนจากเดิมที่เราทราบว่า เมื่ออ่านรูปขึ้นมาด้วย PIL บางทีจะอ่านเป็นส่วนอยู่แล้วเช่นรูปนี้


จะเกี่ยวข้องกับคำสั่งในการอ่านคือ size และ tile
i = Image.open("Lenna-gray-raw.tif")
i.size
(512, 512)
i.tile
[('raw', (0, 0, 512, 64), 8, ('L', 0, 1)), ('raw', (0, 64, 512, 128), 32776, ('L', 0, 1)), ('raw', (0, 128, 512, 192), 65544, ('L', 0, 1)), ('raw', (0, 192, 512, 256), 98312, ('L', 0, 1)), ('raw', (0, 256, 512, 320), 131080, ('L', 0, 1)), ('raw', (0, 320, 512, 384), 163848, ('L', 0, 1)), ('raw', (0, 384, 512, 448), 196616, ('L', 0, 1)), ('raw', (0, 448, 512, 512), 229384, ('L', 0, 1))]

หากเราจะใช้ลูปวนอ่าน ก็ต้องเปลี่ยนสองค่านี้ เช่น
ถ้าขนาดรูปเป็น 512 คอลัมน์ x 512 แถว
สมมติว่าอ่านทีละ 64 แถว ก็จะต้องอ่าน 512/64 = 8 ครั้ง

รอบที่ 0
size ก็จะเป็น (512,64)
tile ก็จะเป็น ('raw', (0, 0, 512, 64), 8, ('L', 0, 1))

รอบที่ 1
size ก็จะเป็น (512,64)
tile ก็จะเป็น ('raw', (0, 0, 512, 64), (8+512*64), ('L', 0, 1))

รอบที่ 2
size ก็จะเป็น (512,64)
tile ก็จะเป็น ('raw', (0, 0, 512, 64), (8+512*64+512*64), ('L', 0, 1))

ไปเรื่อยๆ โดยสังเกตว่าในที่นี้ขนาดของ tile เป็น (0, 0, 512, 64) ตลอด

ถ้าสมมติว่า rr เป็นตัวแปรเอาไว้บอกรอบ มีค่าตั้งแต่ 0-7 (8 รอบ) ดั้งนั้น
รอบที่ rr
size ก็จะเป็น (512, 64)
tile ก็จะเป็น ('raw', (0, 0, 512, 64), (8 + (rr*(512*64)), ('L', 0, 1))

สมมติว่าในตัวอย่างแรกนี้ เราจะลองอ่านรูปขึ้นมาทีละส่วน แล้วแปะลงไปในรูปใหม่ ให้ผลลัพธ์หน้าตาเหมือนรูปต้นฉบับเป๊ะ


โค้ดก็จะประมาณนี้ครับ
from PIL import Image, ImageTk
from Tkinter import Tk, Label
img = Image.open("Lenna-gray-raw.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
#total read = 512/64 =8
totalRead = oriH/rowRead

#image header size, please check by img.tile, it is different for images
header = 8;
#loop for each partial read
for rr in range(totalRead):
    #reopen image, necessary due to partial loading
    img = Image.open("Lenna-gray-raw.tif")
    #tile
    offset = rr*(rowRead*oriW)
    img.tile = [('raw', (0, 0, oriW, rowRead),  header + offset, ('L', 0, 1))]
    #reading size eg. 512,64
    img.size = (oriW, rowRead)   
    #load part of image
    img.load()
    #copy part of image to new image
    #paste(source image, top-left corner)
    out.paste(img,(0,rr*rowRead))

#display on Tkinter
root = Tk()
imgTk = ImageTk.PhotoImage(out)
lbl = Label(root, image=imgTk)
lbl.pack()
root.mainloop()
ต่อมา ถ้าเราต้องการประมวลผลแต่ละพิกเซลไปด้วย ในที่นี้เอาแบบง่ายๆคือทำ Image Negative เพื่อให้ได้ผลลัพธ์ดังนี้


โค้ดก็จะประมาณนี้ครับ
from PIL import Image, ImageTk
from Tkinter import Tk, Label
img = Image.open("Lenna-gray-raw.tif")
#create new output image
out = Image.new(img.mode, img.size, None)
pixOut = out.load()

#try to read every 64 rows
rowRead = 64
#size of original image
oriW, oriH = img.size
#total read = 512/64 =8
totalRead = oriH/rowRead

#image header size, please check by img.tile, it is different for images
header = 8;
#loop for each partial read
for rr in range(totalRead):
    #reopen image, necessary due to partial loading
    img = Image.open("Lenna-gray-raw.tif")
    #tile
    offset = rr*(rowRead*oriW)
    img.tile = [('raw', (0, 0, oriW, rowRead),  header + offset, ('L', 0, 1))]
    #reading size eg. 512,64
    img.size = (oriW, rowRead)   
    #load part of image to pixel object
    pix = img.load()
    
    #try to perform pixel processing
    #loop for each row and column
    w,h = img.size
    for r in range(h):
        for c in range(w):
            pixOut[c,r+(rr*rowRead)] = 255-pix[c,r]

#display on Tkinter
root = Tk()
imgTk = ImageTk.PhotoImage(out)
lbl = Label(root, image=imgTk)
lbl.pack()
root.mainloop()

No comments:

Post a Comment