幾何變換

      在〈幾何變換〉中尚無留言

OpenCV有相當多的函數可以進行幾何變換,但真的要用起來,實在不方便。故本篇將其常用的功能集合成一個類別,改寫成一個好用的sdk – class MahalCv

縮放

cv2.resize(src, (新寬, 新高), 內插值方式)

內插值有如下三種
cv2.INTER_AREA
cv2.INTER_CUBIC(三次插值)
cv2.INTER_LINEAR(線性插值)
cv2.INTER_NEAREST(最近鄰插值)
cv2.INTER_LANCZOS4(lANCZOS插值)
以上的插值法都是為了解決放大縮小時失真的問題,有著非常複雜的演算法。但常用的就二種,CUBIC(速度較慢)及LINEAR(速度較快)

import cv2
from mcv import mcv
buddha=cv2.imread('buddle.jpg')
dst=mcv.resize(buddha, 0.2)
cv2.imshow("Buddle",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#sdk如下
class MahalCv():
@staticmethod
def resize(src, w=None, h=None, scale=1):
if w is None or h is None:
h, w = src.shape[:2]
w = int(w * scale)
h = int(h * scale)
dst = cv2.resize(src, (w, h), interpolation=cv2.INTER_LINEAR)
return dst

#應用如下
from MahalCv import MahalCv as cv
img=cv.read('buddha.jpg')
img=cv.resize(img, 800,600)

影像裁切

想要取得影像中的某個區塊,可直接指定列及行。請注意,numpy的第一維為列,第二維為行,第三維為bgr值

import cv2
img_bgr=cv2.imread('tiger.jpg')
cv2.namedWindow('Tiger', cv2.WINDOW_NORMAL)
img=img_bgr[1800:2900, 2200:3200]#[列1:列2, 行1:行2]
cv2.imshow('Tiger', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#sdk如下
@staticmethod
def crop(src, x1, y1, x2, y2):
dst=src[y1:y2, x1:x2].copy()
return dst

平移

cv2.warpAffine(src, m, (新尺寸))

m 為平移參數。[1, 0. 500] 為水平平移,[0,1,500]為垂直平移
新尺寸為tuple型態, 是整個影像裁切後的尺寸,不是縮放後的尺寸,所以一般都是原始長寬。最後才使用resize縮放。

import cv2
from Mahalcv import Mahalcv
buddha=cv2.imread('buddle.jpg')
dst=Mahalcv.shift(buddha, 500,500)
dst=Mahalcv.resize(dst, 0.2)
cv2.imshow("Buddle",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#sdk如下
@staticmethod
def shift(src, x, y):
m = np.float32([[1, 0, x], [0, 1, y]])
h, w = src.shape[:2]
dst = cv2.warpAffine(src, m, (w, h))
return dst

旋轉

cv2.getRotationMatrix2D((中心x, 中心y), 角度, 縮放)

import cv2
from Mahalcv import Mahalcv
buddha=cv2.imread('buddle.jpg')
h, w, channel=buddha.shape
dst=Mahalcv.rotation(buddha, 45, 0.5)
nw=800
buddha=cv2.resize(buddha, (nw,int(nw*h/w)), interpolation=cv2.INTER_LINEAR)
dst=cv2.resize(dst, (nw,int(nw*h/w)), interpolation=cv2.INTER_LINEAR)
cv2.imshow("normal", buddha)
cv2.imshow("image", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#sdk如下
@staticmethod
def rotation(src, angle, x=None, y=None, scale=1):
h, w = src.shape[:2]
if x is None or y is None:#以中心點旋轉
x=(w-1)/2
y=(h-1)/2
m = cv2.getRotationMatrix2D((x, y), angle, scale)
dst = cv2.warpAffine(src, m, (w, h))
return dst

鏡射

import cv2
from Mahalcv import Mahalcv, Direction
buddha=cv2.imread('buddle.jpg')
dst=Mahalcv.flip(buddha, direction=Direction.HORIZONTAL)
dst=Mahalcv.resize(dst, 0.2)
cv2.imshow("Buddle",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#sdk如下
from enum import Enum, IntEnum
import cv2
import numpy as np
class Direction(IntEnum):
HORIZONTAL=1
VERTICAL=0
BOTH=-1
class MahalCv():
@staticmethod
def flip(src, direction=Direction.HORIZONTAL):
return cv2.flip(src, direction)

透視圖(Prespective)

透視圖可以將非水平或非垂直的線拉直,如下圖所示

底下程式中,先選取原圖的四個點產生pts1陣列,其順序如上圖所示,依序為左上,右上,左下,右下。其座標為(x, y)。然後再選取要貼上的四個點pts2, 然後用getPerspectiveTransform()產生變換矩陣M, 再使用warpPerspective產生結果。

import cv2
import numpy as np
import pylab as plt
img=cv2.imread('buddle.jpg')
pts1 = np.float32([[2000,0],[2800,0],[1500, 1500],[3500,1500]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(img),plt.title('Input')
plt.subplot(122),plt.imshow(dst),plt.title('Output')
plt.show()

多張影像相加

若有多張影像要合成一張,則要考慮是前面蓋掉後面,或是每張都有其權重。多張影像相疊在一起可以使用cv2.addWeighted()函數。另需注意,每張影像的長寬皆必需一樣,才可以相加。底下是採用權重相加的效果

import numpy as np
import cv2
buddha=cv2.imread('buddle.jpg')
child=cv2.imread('child.jpg')
buddha=buddha[0:3000, 0:4000]
child=child[0:3000, 0:4000]
cv2.namedWindow('merge', cv2.WINDOW_NORMAL)
merge=cv2.addWeighted(buddha,0.4, child, 0.6, 0)#使用權重相加
cv2.imshow('merge', merge)
cv2.waitKey(0)
cv2.destroyAllWindows()

上述addWeighted()的最後一個參數,為亮度,0為不變,愈大就愈接近白色(255)

np及cv2的相加,有所不一樣,請看如下代碼

x=np.uint8([250])
y=np.uint8([10])
print(cv2.add(x,y)) #會得到最高上限值 255
print(x+y) # 會得到除以256後的餘數
結果 :
[[255]]
[4]

從網路下載圖片

從網路上下載圖片, 需使用 urllib套件。此套件系統本身就有了,不需另行安裝。經由urllib讀入的byte, 經由np.asarray()轉換後,就是PIL的格式了。np 或PIL格式的圖片,再經由cv2.imdecode()即可轉成cv2格式

from urllib.request import urlopen
import numpy as np
import cv2
from MahalCv import MahalCv as cv
url='https://login.sina.com.cn/cgi/pin.php?r=9967937&s=0&p=gz-d0dc363f6a4523cbd602a5a10f00c59b4784'
resp = urlopen(url)
image = np.asarray(bytearray(resp.read()), dtype="uint8")
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
cv.show('title', image)
cv.wait()

OpenCv to PIL

使用Image.fromarray()即可轉換

import cv2
from PIL import Image
import numpy
img = cv2.imread("plane.jpg")
cv2.imshow("OpenCV",img)
image = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
image.show()
cv2.waitKey()

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *