OpenCVバージョン: 4.6.0.66
アルゴリズム実装のアイデア:
- 色認識(赤)
- 形態学的ノイズ除去
- 輪郭検出
- ポリゴンフィッティング
- 遠近法補正
コード:
import cv2
import numpy as np
# 可视化
def img_show(name, img):
cv2.namedWindow(name, 0)
cv2.resizeWindow(name, 1000, 500)
cv2.imshow(name, img)
cv2.waitKey(0)
def color_warped(path):
img = cv2.imread(path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 颜色识别(红色),过滤红色区域
lower_red1 = np.array([0, 43, 46]) # 红色阈值下界
higher_red1 = np.array([10, 255, 255]) # 红色阈值上界
mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)
lower_red2 = np.array([156, 43, 46]) # 红色阈值下界
higher_red2 = np.array([180, 255, 255]) # 红色阈值上界
mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)
mask_red = cv2.add(mask_red1, mask_red2) # 拼接过滤后的mask
img_show('mask_red', mask_red)
# 形态学去噪,cv2.MORPH_OPEN先腐蚀再膨胀,cv2.MORPH_CLOSE先膨胀再腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_OPEN, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_CLOSE, kernel, iterations=3)
img_show('mask_red', mask_red)
# 轮廓检测,找出线条的轮廓
draw_cnt = img.copy()
cnts = cv2.findContours(mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
cv2.drawContours(draw_cnt, cnts, -1, (0, 255, 0), 2)
img_show('draw_cnt', draw_cnt)
# 四边形拟合,找到相应的的顶点
draw_approx = img.copy()
point1, point2 = list(), list()
for cnt in cnts:
for epsilon in range(50):
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
break
cv2.polylines(draw_approx, [approx], True, (0, 0, 255), 2) # 绘制边
for i in approx:
cv2.circle(draw_approx, i[0], 6, (0, 0, 0), -1) # 绘制顶点
approx = [i[0] for i in approx.tolist()]
approx = sorted(approx, key=lambda k: k[1], reverse=False) # 按y坐标排序,升序
point1.extend(approx[:2]) # 存放上顶点坐标
point2.extend(approx[2:]) # 存放下顶点坐标
point1.sort(key=lambda k: k[0], reverse=False) # 按x坐标排序,升序
point2.sort(key=lambda k: k[0], reverse=False)
img_show('draw_approx', draw_approx)
# 透视矫正目标区域
w, h = 900, 300
rect = [point1[0], point1[-1], point2[-1], point2[0]] # 顺序为第一个四边形的左上,第四个四边形的右上,第四个四边形的右下,第一个四边形的左下
pts1 = np.array(rect, dtype="float32")
pts2 = np.array([rect[0], [rect[0][0] + w, rect[0][1]],
[rect[0][0] + w, rect[0][1] + h], [rect[0][0], rect[0][1] + h]], dtype="float32")
M = cv2.getPerspectiveTransform(pts1, pts2) # 变换矩阵
img_warped = cv2.warpPerspective(img, M, (1500, 500)) # 透视变换
img_show('img_warped1', img_warped)
img_warped = img_warped[rect[0][1]: rect[0][1] + h, rect[0][0]: rect[0][0] + w] # 抠出变换后的区域
img_show('img_warped2', img_warped)
if __name__ == '__main__':
path = 'data/picture/18.jpg'
color_warped(path)
元の画像:
色認識(赤)
img = cv2.imread(path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
色認識に使用されるチャネルはHSVチャネルです。HSV チャネルを使用して色の識別を行うと、BGR チャネルを使用するよりも区別しやすくなります。HはHue(色相、色相、値:0~180)、SはSaturation(彩度、色純度、値:0~255)、VはValue(明るさ、値:0~255)、詳細表示:HSV色空間。各色の値の範囲は次のとおりです。
赤には 2 つの値の範囲があり、これら 2 つの範囲はほとんどの場合補完的な関係にあり、実際の状況に応じて調整できることが わかります。
# 颜色识别(红色),过滤红色区域
lower_red1 = np.array([0, 43, 46]) # 红色阈值下界
higher_red1 = np.array([10, 255, 255]) # 红色阈值上界
mask_red1 = cv2.inRange(hsv, lower_red1, higher_red1)
lower_red2 = np.array([156, 43, 46]) # 红色阈值下界
higher_red2 = np.array([180, 255, 255]) # 红色阈值上界
mask_red2 = cv2.inRange(hsv, lower_red2, higher_red2)
mask_red = cv2.add(mask_red1, mask_red2) # 拼接过滤后的mask
フィルタリングされたバイナリ イメージは次のとおりです。
形態学的ノイズ除去
# 形态学去噪,cv2.MORPH_OPEN先腐蚀再膨胀,cv2.MORPH_CLOSE先膨胀再腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_OPEN, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
mask_red = cv2.morphologyEx(mask_red, cv2.MORPH_CLOSE, kernel, iterations=3)
色認識ではノイズの一部も一緒に認識されることがありますが、このとき形態学を利用してノイズ除去を行うことができます。形態学的ノイズ除去にcv2.morphologyEx を使用する前に、コンボリューション カーネルの形状とサイズをcv2.getStructuringElementによって定義する必要があります。
cv2.getStructuringElement(shape, ksize) の共通パラメータは次のとおりです。
- 形状: カーネルの形状、cv2.MORPH_RECT (長方形)、cv2.MORPH_CROSS (十字)、cv2.MORPH_ELLIPSE (楕円)
- ksize: コアのサイズ (幅, 高さ) の形式
cv2.morphologyEx(src, op, kernel, iterations) の 共通パラメータは次のとおりです。
- src: 入力画像
- op: モルフォロジー演算のタイプ、cv2.MORPH_ERODE (侵食)、cv2.MORPH_DILATE (膨張)、cv2.MORPH_OPEN (オープン演算)、cv2.MORPH_CLOSE (クローズ演算)、cv2.MORPH_GRADIENT (勾配演算)、cv2.MORPH_TOPHAT (トップハット演算)、cv2.MORPH_BLACKHAT (ブラック ハット演算)、詳細を参照:形態素演算
- カーネル:形態素演算用の畳み込みカーネル
- iterations: 形態学的操作の反復数、デフォルト値は1です。
効果は次のとおりです。
輪郭検出
# 轮廓检测,找出线条的轮廓
draw_cnt = img.copy()
cnts = cv2.findContours(mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
cv2.drawContours(draw_cnt, cnts, -1, (0, 255, 0), 2)
cv2.findContours(image,mode,method) を使用して輪郭を検出します。共通パラメータは次のとおりです。
- 画像:バイナリ画像
- mode: 輪郭の取得モード
cv2.RETR_EXTERNAL 外側の輪郭のみを検出 cv2.RETR_LIST 検出された輪郭は階層関係を確立しません cv2.RETR_CCOMP 輪郭は 2 レベル設定され、上層が外周境界、内層が内穴の境界情報となります。内側の穴に別の接続されたオブジェクトがある場合、このオブジェクトの境界も最上層にあります cv2.RETR_TREE 階層ツリー構造のアウトラインを構築する
- 方法: 輪郭の近似方法
cv2.CHAIN_APPROX_NONE すべての輪郭点を保存し、隣接する 2 つの点間のピクセル位置の差が 1 を超えないようにします。 cv2.CHAIN_APPROX_SIMPLE 要素を水平方向、垂直方向、斜め方向に圧縮し、その方向の終了座標のみを保持します
cv2.drawContours を使用して輪郭を描画します。効果は次のとおりです。
近似多角形
# 四边形拟合,找到相应的的顶点
draw_approx = img.copy()
point1, point2 = list(), list()
for cnt in cnts:
for epsilon in range(50):
approx = cv2.approxPolyDP(cnt, epsilon, True)
if len(approx) == 4:
break
cv2.polylines(draw_approx, [approx], True, (0, 0, 255), 2) # 绘制边
for i in approx:
cv2.circle(draw_approx, i[0], 6, (0, 0, 0), -1) # 绘制顶点
ポリゴンを近似するにはcv2.estimatePolyDP(curve, epsilon, Closed) を使用します。一般的なパラメータは次のとおりです。
- 曲線:入力2 次元点セットの配列
- ε:近似結果の精度。これは、元の曲線とその近似曲線の間の最大距離です。イプシロンが小さいほど、近似結果のポリラインの形状は曲線に近づきます。詳細については、「近似ポリゴン」を参照してください。
- 閉じた: TrueまたはFalse。True は近似曲線が閉じている(最初の頂点が最後の頂点に接続されている) ことを示し、False は近似曲線が閉じていないことを示します
cv2.estimatePolyDP は近似多角形の頂点座標を返します. ここで,イプシロン精度は 範囲内の値でトラバースされます. 返される頂点座標の数が4の場合, それは四角形になります.
各輪郭に対して四角形フィッティングを実行し、cv2.polylinesとcv2.circleを使用してエッジと頂点をそれぞれ描画します。効果は次のとおりです。
四辺形を当てはめた後、各四辺形の頂点が並べ替えられます。
遠近法補正
# 透视矫正目标区域
w, h = 900, 300
rect = [point1[0], point1[-1], point2[-1], point2[0]] # 顺序为第一个四边形的左上,第四个四边形的右上,第四个四边形的右下,第一个四边形的左下
pts1 = np.array(rect, dtype="float32")
pts2 = np.array([rect[0], [rect[0][0] + w, rect[0][1]],
[rect[0][0] + w, rect[0][1] + h], [rect[0][0], rect[0][1] + h]], dtype="float32")
M = cv2.getPerspectiveTransform(pts1, pts2) # 变换矩阵
img_warped = cv2.warpPerspective(img, M, (1500, 500)) # 透视变换
透視変換にcv2.warpPerspective を使用する前に、cv2.getPerspectiveTransformによって変換行列を取得する必要があります。
cv2.getPerspectiveTransform(src, dst) の共通パラメータは次のとおりです。
- src:変換前の画像四角形の頂点座標(配列) (3 点が同一線上にない場合)
- dst:変換されたイメージの四角形の頂点座標(配列) 。ここで、3 つの点は同一線上にありません。
ここでは、変形前の四角形の頂点座標を入力します。1つ目の四角形の左上座標、4つ目の四角形の右上座標、4つ目の四角形の右下座標、 1つ目の四角形の左下座標です。四角形; 変形した四角形の頂点を入力 座標は、最初の四角形の左上の座標の幅と高さを拡張します。
cv2.getPerspectiveTransform(src, M, dsize) の共通パラメータは次のとおりです。
- src: 入力画像
- M: 変換行列
- dsize: 出力画像サイズ
変身効果は以下の通りです。
img_warped = img_warped[rect[0][1]: rect[0][1] + h, rect[0][0]: rect[0][0] + w] # 抠出变换后的区域
変換された領域を切り取ると、次のような効果が得られます。
参考リンク
3 分で RGB、HSV、HSL の色空間をすばやく学習 - プログラマーが求めた
第 8 章 形態素演算 -- 8.3 カーネル関数 cv2.getStructuringElement()
Python +OpenCV CH9: 形態素演算 (morphologyEx 拡張機能)_liguoxin1990 のブログ - CSDN ブログ
ポリゴン近似 cv2.estimatedPolyDP と Douglas-Peucker アルゴリズム_00000cj のブログ-CSDN ブログ_ポリゴン近似アルゴリズム