色彩模型
色彩模型是指要用何種數位方式,來描述我們所認知的顏色。
國小的課程中總是教我們這世間的所有顏色都是由紅橙黃綠藍靛紫七種色彩組成,所以才有彩虹的原故。
但到了國中高中的物理學,才發現這根本就是騙小孩的,而且大錯特錯。要構成這宇宙中的所有顏色(包含人類眼睛看不到的顏色),其實可以有很多種方式達成。七原色根本就不是 “原色”。
常見的色彩模型有RGB(光源),CMYK(墨水),GrayScale(灰階),HSV(色調/飽和度/色值),HSL(色調/飽和度/亮度)。
RGB/RGBA
初期的電腦,因為效能及記憶体有限的原故,使用紅綠藍三種顏色(Channel)來調配,每種顏色的強度值使用8bit記錄,其值為 0~255。所以三種顏色共使用24bit, 因此可形成 2^24=1677萬色。
但好死不死,人類最愛的黃金色並不在這1677萬色之中,所以只好再加入一個Alpha Channel(透明背景),變成RGBA, 總共使用了32bit來記錄。因此共可以展現 2^32=4096M=4G=42億種顏色,這已遠遠超出人類眼睛所能辨識的範圍了。
OpenCV色彩模型
OpenCV經由cv2.imread()讀取的資料格式為numpy三維陣列,其色彩模型為BGR格式,可用如下方式進行轉換
img_rgb=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_rgb=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_hsv=cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
Matplotlib顯圖
matplotlib除了可繪製圖表外,亦可顯示圖片,但其色彩模型為RGB。所以可以使用如下三種方式轉碼
img=img[:,:,::-1].copy()
img=img[...,::-1].copy()
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
完整代碼如下
import cv2
import pylab as plt
img_bgr=cv2.imread('tiger.jpg')
axes_bgr=plt.subplot(1,2,1)
axes_bgr.set_xticklabels([])
axes_bgr.set_yticklabels([])
axes_bgr.imshow(img_bgr)
axes_bgr.set_title("BGR")
img_rgb=cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
axes_rgb=plt.subplot(1,2,2)
axes_rgb.set_xticklabels([])
axes_rgb.set_yticklabels([])
axes_rgb.set_title("RGB")
axes_rgb.imshow(img_rgb)
灰階
灰階模式僅有256色。如果要在Matplotlib中顯示灰階照片, 則plt.imshow需加如下參數
plt.imshow(img, cmap='gray')
import cv2
import pylab as plt
img_bgr=cv2.imread('tiger.jpg')
img_gray=cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
plt.xticks([])
plt.yticks([])
plt.title('Gray')
plt.imshow(img_gray, cmap='gray')
plt.show()
遮色片
Photoshop的遮色片,功能非常強大,可以單獨調整R,G,B其中一個Channel的顏色強度。比如紅色遮色片中,其強度值為 0~255,值愈強,就愈紅。
要將RGB三個Channel分別提取出來, 可以使用r, g, b=cv2.split(img_rbg), 或是使用 r=img_rgb(:,:,0) 單獨提取(0為紅色,1為綠色,2為藍色,必需視影像格式)
import cv2
import pylab as plt
img_bgr=cv2.imread('tiger.jpg')
img_rgb=img_bgr[:,:,::-1]
#紅色遮色片
img_mask=img_rgb[:,:,0]
axes_mask=plt.subplot(2,3,1)
axes_mask.set_xticklabels([])
axes_mask.set_yticklabels([])
axes_mask.imshow(img_mask, cmap='gray')
axes_mask.set_title("Red Mask")
#純紅Channel
img=img_rgb[...].copy()
img[:,:, 1] = 0 #G Channel 全變為 0
img[:,:, 2] = 0 #B Channel 全變為 0
axes=plt.subplot(2,3,4)
axes.set_xticklabels([])
axes.set_yticklabels([])
axes.set_title("Red")
axes.imshow(img)
#綠色遮色片
img_mask=img_rgb[:,:,1]
axes_mask=plt.subplot(2,3,2)
axes_mask.set_xticklabels([])
axes_mask.set_yticklabels([])
axes_mask.imshow(img_mask, cmap='gray')
axes_mask.set_title("Green Mask")
#純綠Channel
img=img_rgb[...].copy()
img[:, :, 0] = 0
img[:, :, 2] = 0
axes=plt.subplot(2,3,5)
axes.set_xticklabels([])
axes.set_yticklabels([])
axes.set_title("Green")
axes.imshow(img)
#藍色遮色片
img_mask=img_rgb[:,:,2]
axes_mask=plt.subplot(2,3,3)
axes_mask.set_xticklabels([])
axes_mask.set_yticklabels([])
axes_mask.imshow(img_mask, cmap='gray')
axes_mask.set_title("Blue Mask")
#純藍Channel
img=img_rgb[...].copy()
img[:, :, 0] = 0
img[:, :, 1] = 0
axes=plt.subplot(2,3,6)
axes.set_xticklabels([])
axes.set_yticklabels([])
axes.set_title("Blue")
axes.imshow(img)
plt.show()
split 及 merge
cv2.split()可一次提取 r, g, b 三個Channel。另cv2.merge((b, g, r))則可合併通道,但請注意,merge必需使用tuple
import cv2
img_bgr=cv2.imread('tiger.jpg')
cv2.namedWindow('b', cv2.WINDOW_NORMAL)
cv2.namedWindow('g', cv2.WINDOW_NORMAL)
cv2.namedWindow('r', cv2.WINDOW_NORMAL)
b, g, r=cv2.split(img_bgr)
cv2.imshow('b', b)
cv2.imshow('g', g)
cv2.imshow('r', r)
bgr=cv2.merge((b, g, r))
cv2.imshow('bgr', bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
製作泛黃照片
import cv2 from SDK.Mahalcv import Mahalcv as cv import numpy as np img=cv.read("../tiger.jpg") x=np.uint8([250])#8bit, 不含負數,所以範圍為 0~255 y=np.uint8([10]) print(x+y) # 260%256 print(cv2.add(x,y)) img=cv.resize(img, 1024,768) #製作照片泛黃的效果 b, g, r=cv2.split(img) r=cv2.add(r, 50) g=cv2.add(g, 50) merge=cv2.merge((b,g,r)) cv2.imshow("title", merge) cv2.waitKey(0)