web-dev-qa-db-ja.com

Python:画像から特定の色の領域を切り取る方法(OpenCV、Numpy)

Pythonスクリプトをコード化しようとしています。これは、入力として画像を受け取り、特定の背景色の長方形を切り取ります。しかし、私のコーディングスキルに問題を引き起こすのは、長方形がすべての画像の固定位置にないということです(位置はランダムになります)。

私は派手な関数を管理する方法を本当に理解していません。私もOpenCVについて何かを読みましたが、私はそれにまったく新しいです。これまでのところ、「。crop」関数を使用して画像をトリミングしましたが、固定値を使用する必要があります。

これが入力画像の外観です。黄色の長方形の位置を検出して、画像をそのサイズにトリミングします。

よろしくお願いいたします。

An example of how the picture could look (initial example)

Updated image, how it really looks

編集:@MarkSetchellの方法はかなりうまくいきますが、別のテスト画像の問題が見つかりました。他の画像の問題は、画像の上部と下部に同じ色の2つの小さなピクセルがあり、エラーや不適切なトリミングが発生することです。

4
Keanu

目に見えるのは、側面と上面の暗い灰色の領域と白い灰色の領域、白い領域、そして白い領域の内側に灰色の三角形がある黄色の長方形です。

私が提案する最初の段階は、RGB色空間から [〜#〜] hsv [〜#〜] 色空間に画像を変換することです。
HSV空間の[〜#〜] s [〜#〜]カラーチャネルは、「色飽和チャネル」です。
Sチャネルでは、すべての無色(灰色/黒/白)はゼロであり、黄色のピクセルはゼロより上にあります。

次の段階:

  • Sチャネルにしきい値を適用します(バイナリイメージに変換します)。
    黄色のピクセルは255になり、その他はゼロになります。
  • Threshの輪郭を見つけます(外側の輪郭のみ-長方形のみを見つけます)。
  • 長方形の内側のピクセルの極性を反転します。
    灰色の三角形は255になり、他のピクセルはゼロになります。
  • Threshで輪郭を見つける-灰色の三角形を見つけます。

これがコードです:

import numpy as np
import cv2

# Read input image
img = cv2.imread('img.png')

# Convert from BGR to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Get the saturation plane - all black/white/gray pixels are zero, and colored pixels are above zero.
s = hsv[:, :, 1]

# Apply threshold on s - use automatic threshold algorithm (use THRESH_OTSU).
ret, thresh = cv2.threshold(s, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Find contours in thresh (find only the outer contour - only the rectangle).
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # [-2] indexing takes return value before last (due to OpenCV compatibility issues).

# Mark rectangle with green line
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)

# Assume there is only one contour, get the bounding rectangle of the contour.
x, y, w, h = cv2.boundingRect(contours[0])

# Invert polarity of the pixels inside the rectangle (on thresh image).
thresh[y:y+h, x:x+w] = 255 - thresh[y:y+h, x:x+w]

# Find contours in thresh (find the triangles).
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # [-2] indexing takes return value before last (due to OpenCV compatibility issues).

# Iterate triangle contours
for c in contours:
    if cv2.contourArea(c) > 4:  #  Ignore very small contours
        # Mark triangle with blue line
        cv2.drawContours(img, [c], -1, (255, 0, 0), 2)

# Show result (for testing).
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

HSV色空間のS色チャネル:
enter image description here

thresh-しきい値の後のS:
enter image description here

長方形の極性を反転した後のthresh
enter image description here

結果(四角形と三角形がマークされています):
enter image description here


更新:

背景にいくつかの色の点がある場合、最大の色の輪郭をトリミングできます。

import cv2
import imutils  # https://pypi.org/project/imutils/

# Read input image
img = cv2.imread('img2.png')

# Convert from BGR to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# Get the saturation plane - all black/white/gray pixels are zero, and colored pixels are above zero.
s = hsv[:, :, 1]

cv2.imwrite('s.png', s)

# Apply threshold on s - use automatic threshold algorithm (use THRESH_OTSU).
ret, thresh = cv2.threshold(s, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Find contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = imutils.grab_contours(cnts) 

# Find the contour with the maximum area.
c = max(cnts, key=cv2.contourArea)

# Get bounding rectangle
x, y, w, h = cv2.boundingRect(c)

# Crop the bounding rectangle out of img
out = img[y:y+h, x:x+w, :].copy()

結果:
enter image description here

2
Rotem

Opencvでは、inRangeを使用できます。これは基本的に、指定した範囲の色を白にし、残りを黒にします。これにより、黄色がすべて白になります。

ここにドキュメントがあります: https://docs.opencv.org/3.4/da/d97/tutorial_threshold_inRange.html

1
Mannan Bhardwaj