web-dev-qa-db-fra.com

Python: Comment couper une zone avec une couleur spécifique de l'image (OPENCV, NUMPY)

j'ai donc essayé de coder A Python script, qui prend une image comme entrée, puis coupe un rectangle avec une couleur d'arrière-plan spécifique. Cependant, ce qui cause un problème pour mes compétences de codage, Est-ce que le rectangle n'est pas sur une position fixe dans chaque image (la position sera aléatoire).

Je ne comprends pas vraiment comment gérer les fonctions numpopiques. J'ai aussi lu quelque chose à propos de OpenCV, mais je suis totalement nouveau à cela. Jusqu'à présent, je viens de recadrer les images à travers la fonction "Croprop", mais je devrais ensuite utiliser des valeurs fixes.

C'est ainsi que l'image d'entrée pourrait regarder et maintenant, je voudrais détecter la position du rectangle jaune, puis récolter l'image à sa taille.

L'aide est appréciée, merci d'avance.

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

Updated image, how it really looks

EDIT: @ Way de MarkSetchell fonctionne plutôt bien, mais a trouvé un problème pour une image de test différente. Le problème avec l'autre image est qu'il y a 2 petits pixels de même couleur au sommet et au bas de l'image, qui causent des erreurs ou une mauvaise récolte.

6
Keanu

Ce que je vois, c'est des zones sombres et grises claires sur les côtés et le dessus, une zone blanche et un rectangle jaune avec des triangles gris à l'intérieur de la zone blanche.

La première étape que je suggère de convertir l'image de l'espace de couleur RVB en [~ # ~] HSV [~ # ~] Espace de couleur.
[.____] le [~ # ~] s [~ # ~] canal de couleur dans l'espace HSV, est le "canal de saturation des couleurs".
[.____] Toutes les zéros et les pixels jaunes sont au-dessus des zéros dans le canal S.

Stades suivants:

  • Appliquez le seuil sur S canal (convertir en image binaire).
    [.____] Les pixels jaunes vont à 255 et d'autres vont à zéro.
  • Trouvez des contours dans le battement (ne trouvez que le contour extérieur - seul le rectangle).
  • Inverser la polarité des pixels à l'intérieur du rectangle.
    [.____] Les triangles gris deviennent 255 et d'autres pixels sont des zéros.
  • Trouvez des contours dans Thressh - Trouvez les triangles grises.

Voici le code:

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()

S canal couleur S dans l'espace de couleur HSV:
[.____] enter image description here

thresh - S après seuil:
[.____] enter image description here

thresh après l'inversion de la polarité du rectangle:
[.____] enter image description here

Résultat (rectangle et triangles sont marqués):
[.____] enter image description here


Mettre à jour:

Au cas où il y a des points de couleur en arrière-plan, vous pouvez recadrer le plus grand contour de couleur:

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()

Résultat:
[.____] enter image description here

2
Rotem

Dans OpenCV, vous pouvez utiliser InRange. Cela fait fondamentalement la couleur de la plage que vous avez des problèmes blanches et le reste noir. De cette façon, tout le jaune sera blanc.

Voici la documentation: https://docs.opencv.org/3.4/da/d97/Toryiel_threshold_inrange.html

1
Mannan Bhardwaj