เช่นเดียวกับปัญหาในการอ่านภาพขนาดใหญ่ วิธีที่ง่ายที่สุดคือเพิ่มประสิทธิภาพของคอมพิวเตอร์ เช่น เปลี่ยน CPU หรือเพิ่ม RAM ซึ่งสิ่งที่เสียไปคือค่าใช้จ่าย
หากเลือกช่องทางอื่น เช่นเหมือนกับที่เราพยายามทำ คือการแบ่งส่วนรูปเป็นส่วนย่อยๆ วิธีนี้ก็จะต้องแลกด้วยการเสียเวลาเพิ่มขึ้น เนื่องจาก
- ความซับซ้อนของ Algorithm มากขึ้น
- การอ่านข้อมูลหลายๆครั้งจาก Hard disk น่าจะเสียเวลามากกว่าการอ่านครั้งเดียว
นอกจากนี้ ยังต้องแลกด้วยการเสียหน่วยความจำเพิ่มเติมอีก ได้แก่หน่วยความจำที่ใช้เก็บส่วนของรูปในระหว่างรอประมวลผล
เราลองมาทำการทดลองวัดเฉพาะเรื่องของเวลา ที่ใช้ในการอ่านและประมวลผลรูป ระหว่างการอ่านครั้งเดียว กับการอ่านทีละส่วนกันครับ
วิธีวัดเวลาใน python ก็ตรงไปตรงมาคือ
import time start = time.time() #our codes elapse = time.time()-start
อย่างไรก็ตาม มีข้อสังเกตว่า python มีการสร้าง cache ของรูปที่เคยอ่านไว้ ทำให้การอ่านรูปซ้ำใช้เวลาน้อยกว่าการอ่านรูปครั้งแรก ดังนั้น ในการวัดเวลาครั้งนี้เราจะเอาเวลาโดยประมาณ ที่ไม่รวมการอ่านรูปในรอบแรก
ในที่นี้เราใช้รูปทดสอบขนาด 7076x7001 พิกเซล เป็นรูปแบบ RGB
กรณีที่ 1 อ่านทั้งรูป เวลาที่ใช้โดยประมาณ 0.65 วินาที
from PIL import Image import time #starting time start = time.time() img = Image.open("mfu2009(chs. 1,2,3).tif") #load image img.load() #time used elapse = time.time() - start print elapse
กรณีที่ 2 อ่านทีละส่วนของรูป เวลาที่ใช้โดยประมาณ 1.10 วินาที
from PIL import Image import time #starting time start = time.time() img = Image.open("mfu2009(chs. 1,2,3).tif") #create new output image out = Image.new(img.mode, img.size, None) #try to read every 128 rows rowRead = 128 #keep original rowRead, used when there are extra last set of rows rowReadExtra = rowRead #size of original image oriW, oriH = img.size totalRead = oriH/rowRead #is oriH is divisible by rowRead? rowLeft = oriH%rowRead #image header size, please check by img.tile, it is different for images header = img.tile[0][2]; #loop for each partial read for rr in range(totalRead): #reopen image, necessary due to partial loading img = Image.open("mfu2009(chs. 1,2,3).tif") #------- tile parameters -------- #for grayscale offset = rr*(rowRead*oriW) #if RGB if img.mode=='RGB': offset = offset*3 #if the last set of row is additional if rr==totalRead-1 and rowLeft!=0: rowRead = rowRead + rowLeft #set tile size img.tile = [('raw', (0, 0, oriW, rowRead), header + offset, ('RGB', 0, 1))] #------- size parameters -------- 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*rowReadExtra)) elapse = time.time() - start print elapse
กรณีที่ 3 อ่านทั้งรูป แล้วประมวลผลแต่ละพิกเซล เวลาที่ใช้โดยประมาณ 1.24 วินาที
from PIL import Image import time #starting time start = time.time() img = Image.open("mfu2009(chs. 1,2,3).tif") #load image and perform point processing out = img.point(lambda i: 255-i) #time used elapse = time.time() - start print elapse
กรณีที่ 4 อ่านทีละส่วนของรูป แล้วประมวลผลแต่ละพิกเซล เวลาที่ใช้โดยประมาณ 1.83 วินาที
โค้ดเหมือนกรณีที่ 2 เพียงแค่แก้ไขในส่วนสุดท้ายของลูปนิดหน่อย
from PIL import Image import time #starting time start = time.time() img = Image.open("mfu2009(chs. 1,2,3).tif") #create new output image out = Image.new(img.mode, img.size, None) #try to read every 128 rows rowRead = 128 #keep original rowRead, used when there are extra last set of rows rowReadExtra = rowRead #size of original image oriW, oriH = img.size totalRead = oriH/rowRead #is oriH is divisible by rowRead? rowLeft = oriH%rowRead #image header size, please check by img.tile, it is different for images header = img.tile[0][2]; #loop for each partial read for rr in range(totalRead): #reopen image, necessary due to partial loading img = Image.open("mfu2009(chs. 1,2,3).tif") #------- tile parameters -------- #for grayscale offset = rr*(rowRead*oriW) #if RGB if img.mode=='RGB': offset = offset*3 #if the last set of row is additional if rr==totalRead-1 and rowLeft!=0: rowRead = rowRead + rowLeft #set tile size img.tile = [('raw', (0, 0, oriW, rowRead), header + offset, ('RGB', 0, 1))] #------- size parameters -------- img.size = (oriW, rowRead) #load image part and perform point processing img.load() temp = img.point(lambda i: 255-i) #copy part of image to new image #paste(source image, top-left corner) out.paste(temp,(0,rr*rowReadExtra)) elapse = time.time() - start print elapse
สรุปว่า
กรณีที่ 2 ใช้เวลาเป็น 1.69 เท่าของวิธีที่ 1
กรณีที่ 4 ใช้เวลาเป็น 1.48 เท่าของวิธีที่ 3
นั่นคือ พอจะบอกได้ว่า การแบ่งส่วนอ่านและประมวลผลพิกเซลรูป จะใช้เวลาเพิ่มขึ้นอีกประมาณ 1.5-1.7 เท่าของวิธีปกติ แต่ความเป็นจริงแล้วค่านี้ยังขึ้นอยู่กับหลายปัจจัย ทั้งจำนวนแถวทีอ่านในแต่ละครั้ง อัลกอริธึมในการประมวลผลรูป ขนาดและชนิดของรูป ซึ่งถ้าต้องการได้ค่าที่ถูกต้อง คงต้องทดสอบอีกหลายๆครั้งในหลายๆกรณีครับ