Initial commit with project files

This commit is contained in:
2025-06-27 14:34:11 +02:00
commit 7ea3207e63
310 changed files with 9331 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
# Farbrepräsentation
Die Wahrnehmung von "Farbe" wird in technischen Anwendungen in verschiedenen Formen dargestellt und codiert. Zu
den Grundlagen der Farbrepräsentationen werden in diesem Kapitel Aufgaben und Beispiele bereitgestellt.
Die Aufgaben behandeln die Themengebiete
- **Additive Subtraktive Farbmischung**
- **Farbempfinden und technische Repräsentation von Farbe**
- **Farbmodelle/Farbräume und Konvertierung**
- **Weißabgleich**

View File

@@ -0,0 +1,35 @@
# Übung 1: BGR zu HSV
In dieser Übung wird der HSV Farbraum betrachtet. Die Information der Farbe wird
durch die drei Werte
- H: Helligkeit (Hue)
- S: Sättigung (Saturation)
- V: Value (Helligkeit)
repräsentiert.
In der folgenden Abbildung wird der Farbraum visuell dargestellt:
![alt text](https://upload.wikimedia.org/wikipedia/commons/f/f1/HSV_cone.jpg)
## Aufgabe a)
In der Datei *a.py* wird ein Bild geladen. Nach dem Laden befindet sich das Bild
im BGR-Farbraum. Konvertieren Sie das Bild manuell und
ohne Hilfe von OpenCV in den HSV Farbraum.
Sie können die Rechenvorschriften der Konvertierung von RGB zu HSV aus der [OpenCV-Dokumentation](https://docs.opencv.org/3.4/de/d25/imgproc_color_conversions.html)
nutzen. Beachten Sie, dass die Farbkanäle in OpenCV in BGR und nicht in RGB abgespeichert sind!
## Aufgabe b)
Konvertieren Sie das Bild mithilfe der OpenCV Funktion ```cv2.cvtColor()``` in den HSV
Farbraum. Vergleichen Sie das Ergebnis dann mit dem Ergebnis aus Aufgabenteil a).
Sind die Ergebnisse gleich? Wenn nicht, woran kann es liegen?

View File

@@ -0,0 +1,39 @@
import numpy as np
import cv2
# Einlesen des Bildes
filepath = "../../data/balls.png"
''' a) Manuelles Konvertieren '''
img_norm = img.astype(np.float32) / 255.0
height, width, channels = img.shape
hsv_img = np.zeros_like(img_norm)
for x in range(width):
for y in range(int(height)):
hsv_img = np.round(hsv_img * 255)
hsv_img = hsv_img.astype(np.uint8)
''' b) Konvertieren mit OpenCV '''
hsv_img2 =
''' Das Ergebnis überprüfen '''
img2 = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR)
img3 = cv2.cvtColor(hsv_img2, cv2.COLOR_HSV2BGR)
difference = np.sum(np.abs(img2 - img3))
print("Totale Differenz zwischen den Ergebnissen:", difference)
max_difference = np.max(np.abs(img2 - img3))
print("Maximale Abweichung pro Pixel/Kanal:", max_difference)
example_differences = img2[0:10, 0:10] - img3[0:10, 0:10]
print("Beispiel Differenzen:\n", example_differences)
cv2.imshow("ORIGINAL", img)
cv2.imshow("MANUELL", img2)
cv2.imshow("OPENCV", img3)
cv2.waitKey(0)

View File

@@ -0,0 +1,66 @@
import numpy as np
import cv2
# Einlesen des Bildes
filepath = "../../data/balls.png"
img = cv2.imread(filepath)
''' a) Manuelles Konvertieren '''
img_norm = img.astype(np.float32) / 255.0
height, width, channels = img.shape
hsv_img = np.zeros_like(img_norm)
for x in range(width):
for y in range(int(height)):
minimum = np.min(img_norm[y, x])
b, g, r = img_norm[y, x, 0], img_norm[y, x, 1], img_norm[y, x, 2]
# V Wert
v = np.max(img_norm[y, x].copy())
# S Wert
if v == 0:
s = 0
else:
s = (v - minimum) / v
# H Wert
max_channel_index = np.argmax(img_norm[y, x])
if (v - np.min(img_norm[y, x])) == 0:
h = np.zeros(1)
elif max_channel_index == 2: # Rot
h = 60 * (g - b) / (v - minimum)
elif max_channel_index == 1: # Grün
h = 120 + 60 * (b - r) / (v - minimum)
else: # Blau
h = 240 + 60 * (r - g) / (v - minimum)
if h < 0:
h += 360
h /= (2 * 255)
hsv_img[y, x, 0] = h
hsv_img[y, x, 1] = s
hsv_img[y, x, 2] = v
hsv_img = np.round(hsv_img * 255)
hsv_img = hsv_img.astype(np.uint8)
''' b) Konvertieren mit OpenCV '''
hsv_img2 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
''' Das Ergebnis überprüfen '''
img2 = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR)
img3 = cv2.cvtColor(hsv_img2, cv2.COLOR_HSV2BGR)
difference = np.sum(np.abs(img2 - img3))
print("Totale Differenz zwischen den Ergebnissen:", difference)
max_difference = np.max(np.abs(img2 - img3))
print("Maximale Abweichung pro Pixel/Kanal:", max_difference)
example_differences = img2[0:3, 0:3] - img3[0:3, 0:3]
print("Beispiel Differenzen:\n", example_differences)
cv2.imshow("ORIGINAL", img)
cv2.imshow("MANUELL", img2)
cv2.imshow("OPENCV", img3)
cv2.waitKey(0)

View File

@@ -0,0 +1,32 @@
# Übung 2: BGR zu HSV
In dieser Übung wird der HSV Farbraum betrachtet. Die Information der Farbe wird
durch die drei Werte
- H: Helligkeit (Hue)
- S: Sättigung (Saturation)
- V: Value (Helligkeit)
repräsentiert.
In der folgenden Abbildung wird der Farbraum visuell dargestellt:
![alt text](https://upload.wikimedia.org/wikipedia/commons/f/f1/HSV_cone.jpg)
## Aufgabe a)
Lesen Sie Ihre Kamera aus und geben Sie das Bild "live" wieder.
Konvertieren Sie den eingelesenen Videostream aus Aufgabe in den HSV Farbraum.
Reduzieren Sie die Helligkeit, indem Sie einen der drei Farbkanäle um 30% reduzieren.
Konvertieren Sie das Bild daraufhin zurück in den RGB Farbraum.
Die Lösung findet sich in der Datei [l_a.py](l_a.py).
## Aufgabe b)
Modifizieren Sie Aufgabe a) so, dass die Helligkeit zyklisch zwischen 0% und 100%
variiert.
Die Lösung findet sich in der Datei [l_b.py](l_b.py).

View File

View File

@@ -0,0 +1,24 @@
import numpy as np
import cv2
camera = cv2.VideoCapture(0)
signum = 1
factor = 0.3
while True:
ret, bgr = camera.read()
''' Aufgabe a) '''
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
hsv[:, :, 2] = np.round(hsv[:, :, 2] * factor)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
''' Visualisierung '''
# Display the resulting frame
cv2.imshow('frame', bgr)
if 27 == cv2.waitKey(1): # Taste "q"
break
# When everything done, release the capture
camera.release()
cv2.destroyAllWindows()

View File

@@ -0,0 +1,33 @@
import numpy as np
import cv2
camera = cv2.VideoCapture(0)
signum = 1
factor = 0.3
while True:
ret, bgr = camera.read()
''' Aufgabe a) '''
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
hsv[:, :, 2] = np.round(hsv[:, :, 2] * factor)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
''' Aufgabe b) '''
if factor == 0:
signum = 1
elif factor == 1:
signum = -1
factor += signum * 0.02
factor = min(1, factor)
factor = max(0, factor)
''' Visualisierung '''
# Display the resulting frame
cv2.imshow('frame', bgr)
if 27 == cv2.waitKey(1): # Taste "q"
break
# When everything done, release the capture
camera.release()
cv2.destroyAllWindows()

View File

@@ -0,0 +1,22 @@
# Übung 3: Binärbild Repräsentationen
In dieser Übung werden Darstellungsformen von Binärbildern betrachtet. Sie lernen Binär und Quaternärbäume kennen.
## Aufgabe a) Binärbaum
Gegeben ist folgender Binärbaum:
![](./data/binary_tree.png)
Rekonstruieren Sie die Bildzeile, die durch den Binärbaum dargestellt wird.
Sie können die Aufgabe mit Papier und Stift erledigen. Die Lösung wird in dem Skript *l_a.py* visualisiert.
## Aufgabe b) Quaternärbaum
Gegeben ist folgender Quaternärbaum (Quadtree) mit einer Zuordnung der vier Quadranten:
![](./data/quad_tree.png)
Rekonstruieren Sie das Binärbild, die durch den Quaternärbaum dargestellt wird.
Sie können die Aufgabe mit Papier und Stift erledigen. Die Lösung wird in dem Skript *l_b.py* visualisiert.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,16 @@
import numpy as np
import cv2
line = np.asarray(
[[1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1]],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
# Show image
line = line.astype(np.float64)
cv2.imshow("Binaerbaum", line)
cv2.waitKey(0)

View File

@@ -0,0 +1,32 @@
import numpy as np
import cv2
line = np.asarray(
[
[1,1, 1,1, 1,1, 1,1],
[0,0, 1,1, 1,1, 1,1],
[0,0, 1,1, 0,0, 0,1],
[0,0, 1,0, 0,0, 1,1],
[0,0, 0,0, 0,0, 1,1],
[0,0, 0,0, 0,0, 1,1],
[0,0, 0,0, 1,0, 1,1],
[0,0, 0,0, 1,1, 1,1],
],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
line[::50, 0::2] = 1
line[::50, 1::2] = 0
# Show image
line = line.astype(np.float64)
cv2.imshow("Quadtree", line)
cv2.waitKey(0)

View File

@@ -0,0 +1,25 @@
# Übung 4: Weißabgleich
Bei Digitalaufnahmen lässt sich über Bildverarbeitungssoftware der Weißabgleich zu einem gewissen
Grad per Software korrigieren. Dazu skaliert man die relativen Luminanzen der Kanäle Rot,
Grün und Blau. Die Skalierung wird über eine Multiplikation mit der folgenden Diagonalmatrix
realisiert.
<p align="center">
<img src="https://latex.codecogs.com/svg.image?\begin{bmatrix}&space;R&space;\\G&space;\\B&space;\\\end{bmatrix}&space;=&space;\begin{bmatrix}&space;r_w&space;&&space;0&space;&&space;0\\&space;0&g_w&space;&0&space;\\0&0&b_w&space;\\\end{bmatrix}&space;\cdot\begin{bmatrix}&space;R'&space;\\G'&space;\\B'&space;\\\end{bmatrix}&space;" title="\begin{bmatrix} R \\G \\B \\\end{bmatrix} = \begin{bmatrix} r_w & 0 & 0\\ 0&g_w &0 \\0&0&b_w \\\end{bmatrix} \cdot\begin{bmatrix} R' \\G' \\B' \\\end{bmatrix} " />
</p>
Das Problem ist nun die Parameter für den optimalen Weißpunkt zu wählen.
## Aufgabe a)
Laden Sie das Bild [../../data/obst.png](../../data/obst.png) und geben Sie er aus. Führen Sie danach den Weißabgleich durch.
Wählen Sie als Parameter Werte, sodass die Farbwerte des Pixels an Stelle x=127 y=146 den Farbwert (255, 255, 255) haben.
Zeigen Sie ebenfalls das abgeglichene Bild an. Die Musterlösung findet sich in der Datei [l_a.py](l_a.py).
![](../../data/obst.png)
## Aufgabe b)
Führen Sie den Weißabgleich auf Ihrem Webcam-Stream durch. Sie können die Parameter frei wählen und variieren.
Die Musterlösung findet sich in der Datei [l_b.py](l_b.py).

View File

@@ -0,0 +1,19 @@
import cv2
import numpy as np
img = cv2.imread("../../data/model.png")
#white_balancing_factor = np.asarray([[[1, 1, 1]]])
white_balancing_factor = 255 / img[146, 127].astype(np.float32)
white_balancing_factor = np.expand_dims(white_balancing_factor, 0)
white_balancing_factor = np.expand_dims(white_balancing_factor, 1)
img_balanced = img * white_balancing_factor
img_balanced = np.clip(img_balanced, 0, 255)
img_balanced = img_balanced.astype(np.uint8)
cv2.imshow("Normal", img)
cv2.imshow("Abgeglichen", img_balanced)
cv2.waitKey()

View File

@@ -0,0 +1,16 @@
import cv2
import numpy as np
white_balancing_factor = np.asarray([[[0.5, 0.3, 0.95]]])
cap = cv2.VideoCapture(0)
while True:
ret, img = cap.read()
img_balanced = img * white_balancing_factor
img_balanced = np.clip(img_balanced, 0, 255)
img_balanced = img_balanced.astype(np.uint8)
cv2.imshow("Normal", img)
cv2.imshow("Abgeglichen", img_balanced)
cv2.waitKey(1)

View File

@@ -0,0 +1,45 @@
# Übung 5: Kettencode
Eine Variante für die Abbildung von Konturen is der Kettencode. Im folgenden sollten Bilder in den Kettencode codiert und
Kettencodes in Konturen decodiert werden.
Für die Codierung mit dem Kettencode soll folgende Zuordnung verwendet werden:
<p align="center">
<img src="https://latex.codecogs.com/gif.latex?\begin{bmatrix}&space;3&space;&&space;2&space;&&space;1&space;\\&space;4&space;&&space;&&space;0\\&space;5&space;&&space;6&space;&&space;7&space;\end{bmatrix}" />
</p>
Für die Codierung mit dem differentiellen Kettencode soll folgende Zuordnung verwendet werden:
<p align="center">
<img src="https://latex.codecogs.com/gif.latex?\begin{bmatrix}&space;&plus;3&space;&&space;&plus;2&space;&&space;&plus;1&space;\\&space;4&space;&&space;&&space;0\\&space;-3&space;&&space;-2&space;&&space;-1&space;\end{bmatrix}" />
</p>
## Aufgabe a) Kettencode
Erstellen Sie für das Bild
![](./data/1.png)
einen Kettencode! Beginnen Sie mit dem weißen Pixel oben links und dem Wert 0.
## Aufgabe b) Kettencode
Erstellen Sie das Bild für den Kettencode
```[6 4 6 3 4 5 6 4 2 2 3 2 2 0 0 7 0 2 0 0 7 6]```
## Aufgabe c) Differentieller Kettencode
Erstellen Sie für das Bild aus Aufgabe a)
einen differenziellen Kettencode! Beginnen Sie mit dem Pixel oben links und dem Wert 0.
## Aufgabe d) Differentieller Kettencode
Erstellen Sie das Bild für den differentiellen Kettencode
```[-2 -2 2 -3 1 1 1 -2 -2 0 1 -1 0 -2 0 -1 1 2 -2 0 -1 -1]```
Nutzen Sie als Startrichtung die Richtung 0 nach Definition des Kettencodes.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,34 @@
import numpy as np
import cv2
line = np.asarray(
[
[0,0, 0,0, 0,0, 0,0],
[1,1, 1,0, 1,1, 1,0],
[1,0, 0,1, 1,0, 0,1],
[1,0, 0,0, 0,0, 1,1],
[0,1, 0,1, 1,1, 1,0],
[0,1, 1,0, 0,1, 0,0],
[0,1, 1,0, 0,0, 0,0],
[0,0, 0,0, 0,0, 0,0],
],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
line[::50, 0::2] = 1
line[::50, 1::2] = 0
# Show image
line = line.astype(np.float64)
cv2.imshow("1", line)
cv2.imwrite("./data/1.png", line*255)
cv2.waitKey(0)
chaincode = [0, 0, 7, 0, 2, 0, 0, 7, 6, 4, 6, 4, 6, 3, 4, 5, 6, 4, 2, 2, 3, 2]
print(chaincode)

View File

@@ -0,0 +1,29 @@
import numpy as np
import cv2
line = np.asarray(
[
[0,0, 0,0, 0,0, 0,0],
[1,1, 1,0, 1,1, 1,0],
[1,0, 0,1, 1,0, 0,1],
[1,0, 0,0, 0,0, 1,1],
[0,1, 0,1, 1,1, 1,0],
[0,1, 1,0, 0,1, 0,0],
[0,1, 1,0, 0,0, 0,0],
[0,0, 0,0, 0,0, 0,0],
],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
line[::50, 0::2] = 1
line[::50, 1::2] = 0
# Show image
line = line.astype(np.float64)
cv2.imshow("b", line)
cv2.waitKey(0)

View File

@@ -0,0 +1,33 @@
import numpy as np
import cv2
line = np.asarray(
[
[0,0, 0,0, 0,0, 0,0],
[1,1, 1,0, 1,1, 1,0],
[1,0, 0,1, 1,0, 0,1],
[1,0, 0,0, 0,0, 1,1],
[0,1, 0,1, 1,1, 1,0],
[0,1, 1,0, 0,1, 0,0],
[0,1, 1,0, 0,0, 0,0],
[0,0, 0,0, 0,0, 0,0],
],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
line[::50, 0::2] = 1
line[::50, 1::2] = 0
# Show image
#line = line.astype(np.float64)
#cv2.imshow("1", line)
#cv2.imwrite("./data/1.png", line*255)
#cv2.waitKey(0)
chaincode = [0, 0, -1, 1, 2, -2, 0, -1, -1, -2, 2, -2, 2, -3, 1, 1, 1, -2, -2, 0, 1, -1]
print(chaincode)

View File

@@ -0,0 +1,29 @@
import numpy as np
import cv2
line = np.asarray(
[
[0,0, 0,0, 0,0, 0,0],
[1,1, 1,0, 1,1, 1,0],
[1,0, 0,1, 1,0, 0,1],
[1,0, 0,0, 0,0, 1,1],
[0,1, 0,1, 1,1, 1,0],
[0,1, 1,0, 0,1, 0,0],
[0,1, 1,0, 0,0, 0,0],
[0,0, 0,0, 0,0, 0,0],
],
)
# Resize image
line = np.repeat(line, 50, axis=1)
line = np.repeat(line, 50, axis=0)
# Add seperators
line[0::2, ::50] = 1
line[1::2, ::50] = 0
line[::50, 0::2] = 1
line[::50, 1::2] = 0
# Show image
line = line.astype(np.float64)
cv2.imshow("d", line)
cv2.waitKey(0)

View File

@@ -0,0 +1,39 @@
# Übung 6: Additive / Subtraktive Farbmischung
In dieser Übung soll die Additive und Subtraktive Farbmischung betrachtet werden.
Es soll ein simples Bild mit der Auflösung 500x300 (BxH) erstellt und angezeigt werden, in der jeweils
von oben aufsteigend jeweils 50 Pixel in der Farbe
- rot
- orange
- gelb
- grün
- blau
- lila
In dieser Übung haben Sie die beiden Farbrepräsentationen "Additiv BGR" und "Subtraktiv BGR" zur Verfügung.
In der folgenden Tabelle sind beide Repräsentationen dargestellt:
| Additiv | Subtraktiv |
| --- | --- |
|![./data/add.png](./data/add.png) | ![./data/add.png](./data/sub.png)|
Bei der Additiven Farbmischung wird eine Farbe durch das Hinzufügen von Farbe zum Komplementär Schwarz erreicht.
Auf dem Rechner entsprechen daher höhere Werte in einem Farbkanal einer stärkeren Präsenz der Farbe im resultierenden
Pixel.
Bei der Subtraktiven Farbmischung wird eine Farbe durch das Abziehen von Farbe zum Komplementär Weiß erreicht.
Auf dem Rechner entsprechen daher höhere Werte in einem Farbkanal einer geringeren Präsenz der Farbe im resultierenden
Pixel.
## Aufgabe a)
In der Datei [a.py](a.py) ist ein leeres Bild vordefiniert. Ergänzen Sie die Farben, um das Bild zu vervollständigen.
In dieser Aufgabe wird eine Farbe im additiven BGR Farbraum dargestellt. Die Musterlösung findet sich in der Datei [l_a.py](l_a.py).
## Aufgabe b)
In der Datei [b.py](b.py) ist ein leeres Bild vordefiniert. Ergänzen Sie die Farben, um das Bild zu vervollständigen.
In dieser Aufgabe wird eine Farbe im subtraktiven BGR Farbraum dargestellt. Die Musterlösung findet sich in der Datei [l_b.py](l_b.py).

View File

@@ -0,0 +1,14 @@
import numpy as np
from color_code import additive_color_plot
img = np.zeros((300, 500, 3), dtype=np.uint8)
img[0:50, 0:500] = [0, 0, 0]
img[50:100, 0:500] = [0, 0, 0]
img[100:150, 0:500] = [0, 0, 0]
img[150:200, 0:500] = [0, 0, 0]
img[200:250, 0:500] = [0, 0, 0]
img[250:300, 0:500] = [0, 0, 0]
additive_color_plot(img)

View File

@@ -0,0 +1,14 @@
import numpy as np
from color_code import subtractive_color_plot
img = np.zeros((300, 500, 3), dtype=np.uint8)
img[0:50, 0:500] = [0, 0, 0]
img[50:100, 0:500] = [0, 0, 0]
img[100:150, 0:500] = [0, 0, 0]
img[150:200, 0:500] = [0, 0, 0]
img[200:250, 0:500] = [0, 0, 0]
img[250:300, 0:500] = [0, 0, 0]
subtractive_color_plot(img)

View File

@@ -0,0 +1,12 @@
import cv2
def additive_color_plot(img):
cv2.imshow("Additive", img)
cv2.waitKey(0)
def subtractive_color_plot(img):
img = 255 - img
cv2.imshow("Subtractive", img)
cv2.waitKey(0)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1,14 @@
import numpy as np
from color_code import additive_color_plot
img = np.zeros((300, 500, 3), dtype=np.uint8)
img[0:50, 0:500] = [0, 0, 255]
img[50:100, 0:500] = [0, 136, 255]
img[100:150, 0:500] = [0, 255, 255]
img[150:200, 0:500] = [0, 255, 0]
img[200:250, 0:500] = [255, 0, 0]
img[250:300, 0:500] = [255, 0, 136]
additive_color_plot(img)

View File

@@ -0,0 +1,14 @@
import numpy as np
from color_code import subtractive_color_plot
img = np.zeros((300, 500, 3), dtype=np.uint8)
img[0:50, 0:500] = [255, 255, 0]
img[50:100, 0:500] = [255, 119, 0]
img[100:150, 0:500] = [255, 0, 0]
img[150:200, 0:500] = [255, 0, 255]
img[200:250, 0:500] = [0, 255, 255]
img[250:300, 0:500] = [0, 255, 119]
subtractive_color_plot(img)