Python OpenCV 365 天學習計劃,與橡皮擦一起進入影像領域吧,本篇博客是這個系列的第 41 篇,
該系列文章導航參考:https://blog.csdn.net/hihell/category_10688961.html
Python OpenCV
- 基礎知識鋪墊
- interplolation 縮放時的插值方式
- 最近鄰插值
- 橡皮擦的小節
基礎知識鋪墊
在 OpenCV 中常見的幾何變換有縮放,仿射,透視變換,之前的內容中已經學習過縮放函式了,今天一邊復習舊知識,一邊學習新知識,
先看一下三個幾何變換對應的函式原型是:
dst = cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
dst = cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
dst = cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
先從縮放說起,函式名為 cv2.resize(),非空引數有 2 個,分別是 src 與 dsize,含義為源影像與縮放后影像的尺寸,
import cv2 as cv
src = cv.imread("./t1.jpg")
cv.imshow("src", src)
dst = cv.resize(src, (200, 200))
cv.imshow("dst", dst)
cv.waitKey(0)
cv.destroyAllWindows()
上述為最簡單的代碼,運行效果如下,實作了一個簡單的變化

該案例會出現一個常見的錯誤,縮放的數值提供的是浮點型別,錯誤提示為
TypeError: integer argument expected, got float
還有需要注意的是,元組 dsize 的兩個值說明如下,順序不要記錯,
# dsize = (cols,rows) 中文,(寬度,高度)
dst = cv.resize(src, (400, 200))
這個地方深究下去,其實需要記憶的細節很多,例如在笛卡爾坐標系里面,記錄一個坐標點都是先 x 軸,后 y 軸,但是在計算機中,影像是以矩陣的形式保存的,先行后列,所以 寬x高x通道 的圖片會保存在 高x寬x通道的三位陣列中,在影像處理的時候,都是按照 高x寬x通道記憶,例如通過 shape 獲取形狀,
src = cv.imread("./t1.jpg")
print(src.shape)
輸出的結果就是 (高,寬,通道),但是這一點 resize 函式沒有遵守,它依舊采用的是 (寬,高) 設定,
fx,fy為影像x,y方向的縮放比例,使用該引數,需要提前將 dsize 設定為 (0,0),測驗代碼如下:
import cv2 as cv
src = cv.imread("./t1.jpg")
print(src.shape)
cv.imshow("src", src)
# dsize = (cols,rows) 中文,(寬度,高度)
dst = cv.resize(src, (0, 0),fx=0.5,fy=0.5)
cv.imshow("dst", dst)
cv.waitKey(0)
cv.destroyAllWindows()
測驗結果為,如果不提前設定 dsize 為 (0,0),那 fx 與 fy 不會生效,注意 dsize=(0,0),如果資料型別不對,會出現如下錯誤:
SystemError: new style getargs format but argument is not a tuple

interplolation 縮放時的插值方式
interplolation 為縮放時的插值方式,有以下幾種方式,這些是今天要探索的重點內容,
cv.INTER_NEAREST:最近鄰插值;cv.INTER_LINEAR:雙線形插值(默認設定);cv.INTER_CUBIC:4x4 像素鄰域的雙三次插值;cv2.INTER_AREA:基于區域像素的重采樣,它可能是影像抽取的首選方法,因為它會產生無云紋理的結果, 但是當影像縮放時,它類似于INTER_NEAREST方法,
最近鄰插值
這部分比較吃精力,所以今天這一個小時,我們爭取搞定一個插值演算法,即最近鄰插值就好,
這個演算法的思想是,通過已經像素值去獲取目標像素值,我在學習的時候找到最通俗的解釋,接下來由我說明給你,
假設有一個 3x3 的灰度圖,需要通過最近鄰插值演算法,得到一個 4x4 的灰度圖,

先通過坐標系去了解像素在縮放的時候的變化,

上圖中最后可以到的結論是:
- 目標像素的 x 值 = 原像素的 x 值 * 倍數;
- 目標像素的 y 值 = 原像素的 y 值 * 倍數;
本案例的倍數是多少呢?很容易計算,原來的影像是 3x3,現在是 4x4,那倍數在 x,y 上都是 4/3 = 0.75,
先看一下運算之后得到的結果如下所示:

這里列舉兩個點的像素值計算,拿目標影像 4x4灰度圖 中的 (3,0) 與 (3,3) 兩個點進行說明,
(3x0)點的值等于(3 x 0.75 ≈ 2,0 x 0.75 = 0),原影像(2,0)點的顏色為222,(3x3)點的值等于(3 x 0.75 ≈ 2,3 x 0.75 ≈ 2),原影像(2,2)點的顏色為45;
掌握了原理之后,就可以自己實作這個演算法了,首先看一下 OpenCV 內置的函式實作結果,
import cv2 as cv
import numpy as np
# 最近鄰插值演算法,來源夢想橡皮擦 https://dream.blog.csdn.net/
def nearest_demo(src, multiple_x, multiple_y):
src_y, src_x, src_c = src.shape
tar_x, tar_y, tar_c = src_x*multiple_x, src_y*multiple_y, src_c
# 生成一個黑色的目標影像
tar_img = np.zeros((tar_y, tar_x, tar_c), dtype=np.uint8)
print(tar_img.shape)
# 渲染像素點的值
# 注意 y 是高度,x 是寬度
for y in range(tar_y-1):
for x in range(tar_x-1):
# 計算新坐標 (x,y) 坐標在舊圖中是哪個值
old_y = round(y/multiple_y)
old_x = round(x/multiple_x)
tar_img[y, x] = src[old_y, old_x]
return tar_img
src = cv.imread("./t2.jpeg")
print(src.shape)
cv.imshow("src", src)
# dsize = (cols,rows) 中文,(寬度,高度)
dst = cv.resize(src, (0, 0), fx=2, fy=2, interpolation=cv.INTER_NEAREST)
cv.imshow("dst", dst)
new_dst = nearest_demo(src, 2, 2)
cv.imshow("new_dst", new_dst)
cv.waitKey(0)
cv.destroyAllWindows()
運行之后發現確實官方的演算法更優一些,

橡皮擦的小節
希望今天的 1 個小時你有所識訓,我們下篇博客見~
相關閱讀
技術專欄
- Python 爬蟲 100 例教程,超棒的爬蟲教程,立即訂閱吧
- Python 爬蟲小課,精彩 9 講
今天是持續寫作的第 83 / 100 天,
如果你想跟博主建立親密關系,可以關注同名公眾號 夢想橡皮擦,近距離接觸一個逗趣的互聯網高級網蟲,
博主 ID:夢想橡皮擦,希望大家點贊、評論、收藏,
CSDN認證博客專家
高級產品經理
互聯網從業者
業余編程愛好者
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/260703.html
標籤:AI
