Monday, February 18, 2013

การอ่านภาพและแสดงผลภาพ

มาดูความง่ายของ Python+OpenCV ในการการอ่านภาพและแสดงผลภาพกันครับ


สมมติว่าเรามีไฟล์รูป lena.jpg ที่เดียวกับโค้ดของเราครับ

ก่อนอื่น ถ้าเราใช้ PyScripter เพื่อเขียนโค้ด Python เราอาจจะกำหนดให้ตัว IDE นี้รู้จักโค้ดของ OpenCV โดยกำหนดดังนี้

เลือกเมนู Tools / Options / IDE Options ... แล้วพิมพ์เพิ่มตรง Special packages ว่า ",cv2" ดังรูป

จากนั้นก็เขียนโค้ดแบบนี้ได้เลยครับ
#import OpenCV
import cv2

#Read image file
img = cv2.imread("lena.jpg",cv2.CV_LOAD_IMAGE_UNCHANGED)

#Check if image is loaded
if img==None:
    print "Image is not loaded."
else:
    #create window for output
    cv2.namedWindow("Image Output")
    #show image in this window
    cv2.imshow("Image Output",img)
    #wait for user to press any key
    cv2.waitKey();
    #close all windows
    cv2.destroyAllWindows();

หมายเหตุ
คำสั่ง cv2.imread สามารถกำหนดรูปแบบการอ่านรูปได้ 3 แบบคือ

  • CV_LOAD_IMAGE_UNCHANGED (น้อยกว่า 0) อ่านรูปตามต้นฉบับ รวมถึง alpha channel ด้วยถ้ามี
  • CV_LOAD_IMAGE_GRAYSCALE (0) อ่านรูปให้เป็นสีเทา
  • CV_LOAD_IMAGE_COLOR (มากกว่า 0) อ่านรูปให้เป็น RGB format

OpenCV กับ Python

เทคโนโลยีเปลี่ยนไปเร็วมากครับ OpenCV ก็พัฒนาไปมากเช่นกัน จนขณะนี้กำลังจะก้าวเข้าสู่รุ่น 2.4.4 แล้วครับ ตอนนี้ OpenCV ก็สนับสนุนหลากหลายแพลตฟอร์ม และหลายภาษา ทั้ง C/C++/Java/Python ในบทความนี้เราจะลองมาใช้ OpenCV กับ Python ซึ่งเป็นภาษาที่กำลังได้รับความนิยมสูง เนื่องจากความง่ายในการใช้งานและประสิทธิภาพ โดยลองใช้งานบนวินโดวส์ครับ

วิธีการติดตั้ง
  1. ดาวน์โหลด Python (แนะนำว่าลองเวอร์ชัน 2.7) จาก http://www.python.org หรือ http://portablepython.com/wiki/PortablePython2.7.3.2 (ตัวนี้เป็น portable ไม่ต้องติดตั้งและมี library มาให้มากมาย แนะนำให้ใช้ครับ)
  2. ติดตั้งหรือแตกไฟล์ Python ให้เรียบร้อย สมมติว่าเป็นที่ c:\python หรือ c:\Portable Python 2.7.3.1
  3. ดาวน์โหลด OpenCV จาก http://opencv.org/ สำหรับ windows ก็จะเป็นไฟล์เช่น OpenCV-2.4.4-beta.exe
  4. ใช้โปรแกรมบีบอัดไฟล์เช่น 7-zip เปิดไฟล์ที่ดาวน์โหลดมา
  5. แตกไฟล์ที่อยู่ในโฟลเดอร์ \opencv\build\python\2.7\ ไฟล์ชื่อ cv2.pyd (อาจแตกโฟลเดอร์ตัวอย่าง ชื่อ \opencv\samples\python2\ ด้วย)
  6. สำเนาไฟล์ cv2.pyd ดังกล่าวไปไว้ที่ c:\python\Lib\site-packages หรือ c:\Portable Python 2.7.3.1\App\Lib\site-packages
  7. เสร็จแล้วครับ ง่ายมากมาย
วิธีการใช้งาน
ถ้าเป็นเวอร์ชัน portable สามารถใช้งานโดยเรียกใช้ไฟล์ PyScripter-Portable.exe ซึ่งเป็น IDE สำหรับเขียนโค้ด Python ที่มีมาให้แล้ว


ในบทความถัดไปเราจะลองเริ่มเขียนโค้ดกันครับ

เอกสารอ้างอิงหลัก (สำหรับหัวข้อนี้และถัดไป)

  • opencv.org
  • opencvpython.blogspot.com


Saturday, December 1, 2012

การ crop และ paste รูป

ในบทความนี้ เราจะลองใช้หลักการของการตัดและแปะ เพื่อสร้าง effect แบบง่ายๆให้กับรูป คือการเคลื่อนรูปไปบางส่วน ให้ได้ผลลัพธ์ดังนี้



โดยกำหนดว่าให้มีการเคลื่อนของรูปไปประมาณ 30% ของความกว้างของรูป

ก่อนอื่น ต้องเพิ่มเมนูเช่น
processMenu.add_command(label="Roll", command=self.imgRoll)

แล้วก็สร้าง method คือ imgRoll ดังนี้
def imgRoll(self):
    #assume rolling horizontally by 30% of width
    w,h = self.im.size
    roll = int(0.30*w)
    #crop 2 parts
    part1 = self.im.crop((0,0,roll,h)) #(left, upper, right, lower)
    part2 = self.im.crop((roll,0,w,h))
    #create new image
    imr = Image.new("RGB",(w,h))
    #swap and paste crop images
    imr.paste(part2,(0,0,w-roll,h))
    imr.paste(part1,(w-roll,0,w,h))
    #set image to rolled image
    self.im = imr.copy()
    self.showImage()

การประมวลผลแต่ละพิกเซลของรูป

จากบทความที่แล้ว เราสามารถเข้าถึงพิกเซลของรูปและแก้ไขได้ ซึ่งเป็นกระบวนการที่สำคัญและสามารถประมวลผลภาพแบบซับซ้อนได้ อย่างไรก็ตาม หากเราต้องการเฉพาะการประมวลผลภาพแต่ละพิกเซล (Point Operation) ก็สามารถใช้คำสั่งที่อาจง่ายขึ้นได้ ได้แก่

out = im.point(function)

ตัวอย่างเช่น หากเราต้องการปรับค่า contrast ของรูป ซึ่งทำได้โดยการคูณแต่ละพิกเซลด้วยค่าคงที่ค่าหนึ่ง เช่น 1.5 ก็จะใช้คำสั่ง

out = im.point(lambda i: i*1.5)

(หมายเหตุ lambda เป็นเทคนิคการเขียนฟังก์ชันเฉพาะกิจของ python เรียกว่า anonymous functions เพื่อที่เราจะไม่ต้องเขียนฟังก์ชันใหม่แยกออกมา)

ตัวอย่างผลลัพธ์ที่เราต้องการ





โค้ดของโปรแกรมก็เพิ่มเติมจากเดิมดังนี้
เมนู
        processMenu.add_command(label="Contrast",command=self.imgContrast)

method
    def imgContrast(self):
        self.im = self.im.point(lambda i: i*1.5)
        self.showImage()

หมายเหตุ
1. คำสั่ง Image.point มีผู้ระบุไว้ว่าเร็วกว่าคำสั่ง Image.load ในการประมวลผลพิกเซล หากมีโอกาสจะได้ทดลองวัดความเร็วเปรียบเทียบกันครับ
2. หากต้องการแยกเป็นฟังก์ชันออกมาต่างหาก ก็ทำได้โดย


    def myContrast(self,i):
        return i*1.5

    def imgContrast(self):
        self.im = self.im.point(self.myContrast)
        self.showImage()

การเข้าถึงพิกเซลของรูป

แม้ว่า Python Imaging Library (PIL) จะมีคำสั่งในการประมวลผลภาพหลากหลาย แต่ในบางครั้งเราอาจจะต้องการที่จะประมวลผลแต่ละพิกเซลเอง ก็จะจำเป็นที่จะต้องทราบการอ่านและแก้ไขพิกเซลนั้น

การอ่านพิกเซล จะทำได้โดย
1. อ่านพิกเซลของรูปทั้งหมด แล้วนำไปเก็บไว้ในโครงสร้างข้อมูลที่เรียกว่า pixel access object ที่มีลักษณะคล้ายกับตัวแปรชุดสองมิติ (2D array) โดยใช้คำสั่ง load ดังนี้
pix = im.load()
2. สามารถอ่านค่าของแต่ละพิกเซล โดยใช้คำสั่ง
pix[x,y]
เมื่อ x และ y เป็นพิกัด เริ่มต้นที่มุมซ้ายบน (0,0)

การแก้ไขค่าพิกเซล หลังจากอ่านค่าพิกเซลทั้งหมดแล้ว ทำได้โดย
pix[x,y] = value
ถ้าเป็นรูป grayscale ค่า value จะเป็นเลขโดดๆ ตั้งแต่ 0 ถึง 255
ถ้าเป็นรูป RGB ค่า value จะเป็นเลขชุด เช่น (100,100,100)

ลองดูการเพิ่มเมนูเพื่อทำการกลับสีรูป (inverse) เพื่อให้ได้ผลลัพธ์ดังนี้



โค้ดเฉพาะส่วนของฟังก์ชันนี้ คือ
def imgInverse(self):
    #load an image reference to a special structure like a list
    pix = self.im.load()
    #print pix[0,0]
    #get image size
    w,h = self.im.size
    #if grayscale image
    if self.im.mode=="L":
        #loop for each row and column
        for r in range(h):
            for c in range(w):
                pix[c,r] = 255 - pix[c,r]
                #Note that we can use getpixel(x,y) and putpixel(x,y)
                #but this method is faster
    elif self.im.mode=="RGB":
    #loop for each row and column
        for r in range(h):
            for c in range(w):
                p = pix[c,r]
                pix[c,r] = (255-p[0],255-p[1],255-p[2])
    self.showImage()

ลองเอาไปเชื่อมต่อกับโค้ดก่อนหน้านี้ได้ครับ
อ้างอิง
http://effbot.org/zone/pil-pixel-access.htm