Monday, February 25, 2013

Brightness และ Contrast

เราลองมาปรับค่า brightness โดยการบวกเพิ่มค่าพิกเซล และค่า contrast โดยการคูณเพิ่มค่าพิกเซล ของรูปสีเทา ให้ได้ผลดังนี้ครับ


เราจะใช้คำสั่ง cv2.add() และ cv2.multiply() ซึ่งคำสั่งทั้งสองจะ clamp หรือ saturate พิกเซล (ถ้าค่าต่ำกว่า 0 ให้เป็น 0 และ ถ้าค่าสูงกว่า 255 ให้เป็น 255) โดยอัตโนมัติครับ

โค้ดประมาณนี้ครับ
import cv2

#read image as gray
img = cv2.imread("lena.jpg",cv2.CV_LOAD_IMAGE_GRAYSCALE)

#increase brightness
bri = cv2.add(img,100)
#increase contrast
con = cv2.multiply(img,1.5)

cv2.imshow("Original",img)
cv2.imshow("Brightness",bri)
cv2.imshow("Contrast",con)

cv2.waitKey()
cv2.destroyAllWindows()

ในกรณีที่เป็นรูปสี ที่มีหลาย channel ผมลองโค้ดเดิมแล้วผลลัพธ์ไม่ถูกต้องครับ มันบวกหรือคูณแค่ channel เดียว เลยพยามเปลี่ยนโค้ดให้เป็นเมตริกซ์บวกหรือคูณกัน (ซึ่งอาจจะมีวิธีที่ดีกว่า) ดังนี้ครับ
import cv2
import numpy as np

img = cv2.imread("lena.jpg")

#brightness
a = 100*np.ones_like(img)
bri = cv2.add(img,a)

#contrast

b = np.zeros_like(img)
con = cv2.scaleAdd(img,1.5,b)   #1.5*img + 0


cv2.imshow("Original",img)
cv2.imshow("Brightness",bri)
cv2.imshow("Contrast",con)

cv2.waitKey()
cv2.destroyAllWindows()

ผลลัพธ์

อย่างไรก็ตาม เราสามารถใช้เทคนิคของ NumPy Array มาทำงานนี้ได้ ดังตัวอย่างต่อไปนี้ครับ ซึ่งใช้ได้กับทั้งรูปสีเทาและสีปกติ
import cv2
import numpy as np

img = cv2.imread("lena.jpg")

#increase brightness
bri = img+100.0
#clip in range 0-255
bri = np.clip(bri,0,255)
#convert to uint8
bri = np.uint8(bri)

#increase contrast
con = img*1.5
con = np.clip(con,0,255)
con = np.uint8(con)

cv2.imshow("Original",img)
cv2.imshow("Brightness",bri)
cv2.imshow("Contrast",con)

cv2.waitKey()
cv2.destroyAllWindows()

สังเกตว่า bri = img+100.0 ตัวเลขที่เอาไปบวกมีทศนิยมด้วย เพื่อเปลี่ยนให้ค่า Array จาก uint8 เป็น float เนื่องจาก ถ้าใช้แค่ bri = img+100 ค่าพิกเซลที่เกิน 255 จะถูกทอนค่าลง เช่น 256 ก็จะกลายเป็น 1 (256%255) ทำให้ได้ค่าที่ไม่ถูกต้องครับ

NumPy Array เปรียบเทียบคำสั่งกับ Matlab

อ้างอิงจาก https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html

Matlab --> Python: NumPy
help func --> help ("func")

ndims(a) --> ndim(a) or a.ndim

size(a) --> shape(a) or a.shape

size(a,n) --> a.shape[n-1]

[ 1 2 3; 4 5 6 ] --> array([[1.,2.,3.], [4.,5.,6.]])

[ 1 2 3; 4 5 6 ] --> vstack(([1,2,3],[4,5,6]))

a(end) --> a[-1]

a.' --> a.T or a.transpose()

a.*b --> a*b

a*b --> dot(a,b)

find(a>0.5) --> nonzero(a>0.5)

y=x --> y=x.copy()

y=x(2,:)--> y=x(2,:)

zeros(3,4)--> zeros((3,4))

ones(3,4)--> ones((3,4))

rand(3,4)--> random.rand(3,4)

repmat(a, m, n) --> tile(a, (m, n))

[a b] --> concatenate((a,b),1) or hstack((a,b)) or column_stack((a,b)) or c_[a,b]

[a; b] --> concatenate((a,b)) or vstack((a,b)) or r_[a,b]

Sunday, February 24, 2013

NumPy Array ตอนที่ 5 การเพิ่มสมาชิกและซ้อน Array

สามารถใช้คำสั่ง append() , concatenate(), vstack(), hstack(), dstack() เช่น

>>> a = np.array([1,2])
>>> b = np.append(a,3)
>>> b
array([1, 2, 3])
>>> b = np.append(a,[3,4])
>>> b
array([1, 2, 3, 4])

เรายังสามารถเลือกที่จะเพิ่มแถว หรือ คอลัมน์ได้ แต่ข้อมูลที่จะเพิ่มต้องเท่ากับจำนวนแถวหรือคอลัมน์นั้น

>>> a = np.array([[1,2],[3,4]])
>>> a
array([[1, 2],
       [3, 4]])

>>> b = np.append(a,[[5,6]],axis=0)
>>> b
array([[1, 2],
       [3, 4],
       [5, 6]])

>>> c = np.append(b,[[0],[0],[0]],axis=1)
>>> c
array([[1, 2, 0],
       [3, 4, 0],
       [5, 6, 0]])

คำสั่ง b = np.append(a,[[5,6]],axis=0) สามารถแทนด้วย
b = np.concatenate((a,[[5,6]])) หรือ
b = np.vstack((a,[[5,6]]))

สำหรับรูป มี แถว คอลัมน์ และ channel ถ้าจะให้ง่ายก็คือ
vstack เพิ่มแถว
hstack เพิ่มคอลัมน์
dstack เพิ่มความลึก

NumPy Array ตอนที่ 4 การเปลี่ยนขนาดของ Array

การเปลี่ยนขนาดของ Array
  • ทำให้เหลือ 1 มิติ
สามารถใช้ฟังก์ชัน ravel() เช่น

>>> a = np.array([[1,2],[3,4]])
>>> a
array([[1, 2],
       [3, 4]])

>>> b = a.ravel()
>>> b
array([1, 2, 3, 4])
  • เปลี่ยนเป็น 2 มิติ ขนาดใดๆ
ใช้คำสั่ง array.shape(row,column) เช่น
>>> b.shape = (2,2)
>>> b
array([[1, 2],
       [3, 4]])
หมายเหตุ ถ้าอยากละมิติใดๆไว้ให้ถูกคำนวณเอง ให้ใส่ค่า -1 เช่น
b.shape = (2,-1)
หรือ ใช้คำสั่ง reshape(row,column) เช่น
c = b.reshape(2,2)
หรือ ใช้คำสั่ง resize(row,column) แต่จะเป็นการเปลี่ยน array นั้นแทน เช่น
b.resize(2,2)

ถ้าต้องการเข้าถึงแต่ละสมาชิกของ array ขนาดใดๆ ในลักษณะของ 1 มิติ สามารถใช้คุณสมบัติ array.flat ได้ เช่น
>>> b
array([[1, 2],
       [3, 4]])
>>> for i in b.flat:
...     print i
...     
1
2
3
4

Friday, February 22, 2013

NumPy Array ตอนที่ 3 Index และการเรียกใช้สมาชิก

Indexing
การเข้าถึงสมาชิกของ Array จะทำผ่าน index โดยจะมีค่าเริ่มต้นเป็น 0 1 2 ไปตามลำดับ และสามารถอ้างอิงจากตัวสุดท้ายมาตัวแรก โดยใช้เลข -1 -2 -3 ไป

import numpy as np 
 
a = np.array([7, 9, 4])

a[0]
a[-1]

ผลลัพธ์
7
4

นอกจากนี้ ยังสามารถใช้เครื่องหมาย : เพื่อระบุช่วงของ index ได้ในรูปแบบ
array[start:end:step] โดยผลลัพธ์จะไม่นับค่า end นะครับ เช่น

a[0:2:1]

ผลลัพธ์ 
[7, 9]

ถ้าใส่แค่ค่า end ค่า start จะเป็น 0 และค่า step จะเป็น 1 เช่น

a[:2]

ผลลัพธ์  
[7, 9]

ถ้าไม่ใส่ค่า end ก็จะทำถึงตัวสุดท้าย เช่น

a[0::2]ผลลัพธ์ 
[7, 4]

นั่นคือ
a[:]
ผลลัพธ์ 
[7, 9, 4]

เราสามารถเปลี่ยนค่าสมาชิกหลายๆตัวพร้อมกันได้ โดยใช้หลักการนี้ เช่น

a[1:3] = 0
จะได้
[7, 0, 0]

และสามารถแสดงผลสมาชิกของ array ด้วยคำสั่ง for และ in

for i in a:
      print i**2

จะได้  
49
0
0

สำหรับ array ตั้งแต่สองมิติเป็นต้นไป index ในแต่ละมิติก็จะแยกกันด้วยเครื่องหมาย , เช่น

b = np.array([ ["00","01"], ["10","11"], ["20","21"] ])

[['00', '01'],
['10', '11'],
['20', '21']]

b.shape
(3, 2)

ถ้าต้องการแถวใดๆ

b[1,:]                          # same as b[1]
['10', '11']

ถ้าต้องการหลักใดๆ

b[:,1]
['01', '11', '21']
กรณีที่เป็น array สามมิติ (ซึ่งก็คือ array ของ array สองมิติ)
c = np.array([ [["000","001"],["010","011"],["020","021"]] , [["100","101"],["110","111"],["120","121"]]])

[ [['000', '001'],
    ['010', '011'],
    ['020', '021']],

   [['100', '101'],
    ['110', '111'],
    ['120', '121']] ]

จะกลายเป็นว่า มิติที่ 3 กลายเป็นหลักแรกสุด ตามมาด้วยแถวและหลัก นั่นคือ
c[0,0,1] จะได้ค่า 001
และ

c[0, :, :]
[['000', '001'],
 ['010', '011'],
 ['020', '021']]

นอกจากนี้แล้ว ยังสามารถใช้เครื่องหมาย ... แทนทุกมิติที่ไม่ได้ระบุไว้ เช่น
c[0,...] ก็จะได้ผลลัพธ์เหมือน c[0,:,:]