山内セミナーⅠ(2020/07/15)

関連サイトと資料

サンプル画像


color_spaces.png


lena_image.png


cat-face.png


cat.jpg


lenna.png


cat.png


lenna_250.png


opencv_binary_logo_250.png

morpho_test_imgs.zip

Morphological transformations

形態学的変換は、通常、バイナリイメージに対して実行され、イメージの形状に基づいて実行される操作です。 正確な操作は、操作の性質を決定するカーネル構造化要素によって決定されます。 膨張と収縮は、形態学的変換の分野における2つの基本的な演算子です。 さらに、開閉は、前述の2つの操作(膨張と収縮)から派生した2つの重要な操作です。 最後に、これらの以前の操作のいくつかの違いに基づく他の3つの操作があります。

これらのすべての形態学的変換について、次のサブセクションで説明します。 また、morphological_operations.pyスクリプトは、 これらの変換を一部のテスト画像に適用したときの出力を示します。 要点についても解説します。

Dilation operation

バイナリイメージに対する膨張操作の主な効果は、前景オブジェクトの境界領域を徐々に拡大することです。 つまり、前景オブジェクトの領域が大きくなり、その領域内の穴が縮小します。 操作の詳細を次のコードに示します。

dilation = cv2.dilate(image, kernel, iterations=1)
    

Erosion operation

バイナリイメージに対する侵食操作の主な効果は、前景オブジェクトの境界領域を徐々に侵食することです。 つまり、前景オブジェクトの領域が小さくなり、それらの領域内の穴が大きくなります。 この操作の詳細は、次のコードで確認できます。

erosion = cv2.erode(image, kernel, iterations=1)
    

Opening operation

開始操作では、両方の操作に同じ構造化要素(またはカーネル)を使用して、収縮とそれに続く膨張が実行されます。 このように、侵食を適用して、望ましくないピクセルの小さなグループ(たとえば、ソルトアンドペッパーノイズ)を排除できます。

侵食は画像のすべての領域に無差別に影響します。 浸食後に膨張操作を実行することにより、これらの影響の一部を軽減します。 この操作の詳細は、次のコードで確認できます。

opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    

Closing operation

その反対と同様に、終了演算子は、収縮および膨張操作から導出できます。 この場合、操作は膨張とそれに続く収縮を実行します。 膨張操作は、画像の小さな穴を埋めるために一般的に使用されます。 ただし、拡張操作では、望ましくないピクセルの小さなグループも大きくなります。 膨張後の画像に収縮操作を適用すると、この影響の一部が軽減されます。 この操作の詳細は、次のコードで確認できます。

closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    

Morphological gradient operation

形態勾配操作は、入力画像の膨張と収縮の差として定義されます。

morph_gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)
    

Top hat operation

トップハット演算は、入力画像と画像の開始との差として定義されます。 この操作の詳細は、次のコードで確認できます。

top_hat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT, kernel)
    

Black hat operation

ブラックハット演算は、入力画像と入力画像のクローズとの差として定義されます。 この操作の詳細は、次のコードで確認できます。

black_hat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel)
    

Structuring element

OpenCVは構造化要素に関連して、cv2.getStructuringElement()関数を提供します。

この関数は、目的のカーネル(uint8型のNumPy配列)を出力します。 この関数には、カーネルの形状とサイズの2つのパラメーターを渡す必要があります。 OpenCVは、次の3つの形状を提供します。

Applying morphological transformations to images

morphological_operations.pyスクリプトでは、 さまざまなカーネルのサイズと形状、形態変換、画像を操作します。 このセクションでは、このスクリプトの重要なポイントのいくつかについて説明します。

まず、build_kernel()関数は、カーネルタイプとサイズの両方に基づいて、 モルフォロジー変換で使用する特定のカーネルを返します。 次に、morphological_operationsディクショナリには、 実装されたすべての形態学的操作が含まれます。 辞書をprintで表示すると、出力は次のようになります。

つまり、辞書のキーは、使用する形態学的操作を識別し、 値は、対応するキーが使用されたときに呼び出す関数です。 たとえば、erode操作を呼び出したい場合は、以下を実行する必要があります。

result = morphological_operations[‘erode’](image, kernel_type, kernel_size)
    

上記のコードイメージで、kernel_typeおよびkernel_sizeは関数erodeのパラメーターです (実際、これらはディクショナリのすべての関数のパラメーターです)。

apply_morphological_operation()関数は、 ディクショナリで定義されたすべての形態学的操作を画像の配列に適用します。 最後に、show_images()関数が呼び出され、 配列に含まれるすべての画像がプロットされます。 特定の実装の詳細は、 たくさんのコメントが含まれているmorphological_operations.pyスクリプトのソースコードで確認できます。

このスクリプトは4つの図をプロットし、 さまざまなカーネルタイプとサイズがテストされます。 たとえば、次のスクリーンショットでは、 カーネルサイズが(3、3)および長方形カーネル(cv2.MORPH_RECT)が使用されている場合の出力を確認できます。

上記のスクリーンショットでわかるように、形態学的操作は、 画像の適切な処理を妨げる可能性があるノイズを取り除くことができるため、 画像を前処理するときに便利な手法です。 さらに、モルフォロジー演算を使用して、 画像の構造の不完全性を処理することもできます。

morphological_operations.py
import cv2
import matplotlib.pyplot as plt
import os
	
image_names = ['test1.png', 'test2.png', 'test3.png']
path = 'morpho_test_imgs'
	
kernel_size_3_3 = (3, 3)
kernel_size_5_5 = (5, 5)
	
def load_all_test_images():
    test_morph_images = []
    for index_image, name_image in enumerate(image_names):
        image_path = os.path.join(path, name_image)
        test_morph_images.append(cv2.imread(image_path))
    return test_morph_images
	
def show_images(array_img, title, pos):
    for index_image, image in enumerate(array_img):
        show_with_matplotlib(image, title + "_" + str(index_image + 1),
                             pos + index_image * (len(morphological_operations) + 1))
	
def show_with_matplotlib(color_img, title, pos):
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(len(image_names), len(morphological_operations) + 1, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
	
def build_kernel(kernel_type, kernel_size):
    if kernel_type == cv2.MORPH_ELLIPSE:
        return cv2.getStructuringElement(cv2.MORPH_ELLIPSE, kernel_size)
    elif kernel_type == cv2.MORPH_CROSS:
        return cv2.getStructuringElement(cv2.MORPH_CROSS, kernel_size)
    else:  # cv2.MORPH_RECT
        return cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
	
def erode(image, kernel_type, kernel_size):
    kernel = build_kernel(kernel_type, kernel_size)
    erosion = cv2.erode(image, kernel, iterations=1)
    return erosion
	
def dilate(image, kernel_type, kernel_size):
    kernel = build_kernel(kernel_type, kernel_size)
    dilation = cv2.dilate(image, kernel, iterations=1)
    return dilation
	
def closing(image, kernel_type, kernel_size):
    kernel = build_kernel(kernel_type, kernel_size)
    clos = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
    return clos
	
def opening(image, kernel_type, kernel_size):
    kernel = build_kernel(kernel_type, kernel_size)
    ope = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    return ope
	
def morphological_gradient(image, kernel_type, kernel_size):
    kernel = build_kernel(kernel_type, kernel_size)
    morph_gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)
    return morph_gradient
	
def closing_and_opening(image, kernel_type, kernel_size):
    closing_img = closing(image, kernel_type, kernel_size)
    opening_img = opening(closing_img, kernel_type, kernel_size)
    return opening_img
	
def opening_and_closing(image, kernel_type, kernel_size):
    opening_img = opening(image, kernel_type, kernel_size)
    closing_img = closing(opening_img, kernel_type, kernel_size)
    return closing_img
	
morphological_operations = {
    'erode': erode,
    'dilate': dilate,
    'closing': closing,
    'opening': opening,
    'gradient': morphological_gradient,
    'closing|opening': closing_and_opening,
    'opening|closing': opening_and_closing
}
	
def apply_morphological_operation(array_img, morphological_operation, kernel_type, kernel_size):
    morphological_operation_result = []
    for index_image, image in enumerate(array_img):
        result = morphological_operations[morphological_operation](image, kernel_type, kernel_size)
        morphological_operation_result.append(result)
    return morphological_operation_result
	
for i, (k, v) in enumerate(morphological_operations.items()):
    print("index: '{}', key: '{}', value: '{}'".format(i, k, v))
	
test_images = load_all_test_images()
	
plt.figure(figsize=(16, 8))
plt.suptitle("Morpho operations - kernel_type='cv2.MORPH_RECT', kernel_size='(3,3)'", fontsize=14, fontweight='bold')
	
show_images(test_images, "test img", 1)
	
for i, (k, v) in enumerate(morphological_operations.items()):
    show_images(apply_morphological_operation(test_images, k, cv2.MORPH_RECT, kernel_size_3_3), k, i + 2)
	
plt.show()
	
plt.figure(figsize=(16, 8))
plt.suptitle("Morpho operations - kernel_type='cv2.MORPH_RECT', kernel_size='(5,5)'", fontsize=14, fontweight='bold')
	
show_images(test_images, "test img", 1)
	
for i, (k, v) in enumerate(morphological_operations.items()):
    show_images(apply_morphological_operation(test_images, k, cv2.MORPH_RECT, kernel_size_5_5), k, i + 2)
	
plt.show()
	
plt.figure(figsize=(16, 8))
plt.suptitle("Morpho operations - kernel_type='cv2.MORPH_CROSS', kernel_size='(3,3)'", fontsize=14, fontweight='bold')
	
show_images(test_images, "test img", 1)
	
for i, (k, v) in enumerate(morphological_operations.items()):
    show_images(apply_morphological_operation(test_images, k, cv2.MORPH_CROSS, kernel_size_3_3), k, i + 2)
	
plt.show()
	
plt.figure(figsize=(16, 8))
plt.suptitle("Morpho operations - kernel_type='cv2.MORPH_CROSS', kernel_size='(5,5)'", fontsize=14, fontweight='bold')
	
show_images(test_images, "test img", 1)
	
for i, (k, v) in enumerate(morphological_operations.items()):
    show_images(apply_morphological_operation(test_images, k, cv2.MORPH_CROSS, kernel_size_5_5), k, i + 2)
	
plt.show()
    

Color spaces

このセクションでは、一般的なカラースペースの基本について説明します。 これらの色空間は、RGB、CIE L*a*b*、HSLおよびHSV、およびYCbCrです。

OpenCVは、ユーザーが必要とする変換を実行するための150を超える色空間変換メソッドを提供します。 次の例では、RGBに読み込まれた画像(OpenCVのBGR)から他の色空間(HSV、HLS、YCbCrなど)への変換が実行されます。

Showing color spaces

RGB色空間は、特定の色が赤、緑、青の値で表される加法色空間です。 人間の視覚は同じように機能するため、この色空間はコンピュータグラフィックスを表示する適切な方法です。

CIELAB色空間(CIE L*a*b*または単にLABとも呼ばれます)は、特定の色を3つの数値として表します。 ここで、L*は明度、a*は緑赤のコンポーネント、b*は青黄色を表します。 この色空間は、一部の画像処理アルゴリズムでも使用されます。

色相、彩度、明度(HSL)と色相、彩度、明度(HSV)は2つの色空間であり、 1つのチャネル(H)だけを使用して色を記述するため、色を指定するのが非常に直感的です。 これらのカラーモデルでは、画像処理技術を適用するときに、輝度成分の分離にはいくつかの利点があります。

YCbCrは、ビデオおよびデジタル写真システムで使用される色空間のファミリーであり、 色をクロマコンポーネント(Y)および2つのクロミナンスコンポーネント/クロマ(CbおよびCr)で表します。 この色空間は、YCbCr画像から派生したカラーモデルに基づく画像セグメンテーションで非常に人気があります。

color_spaces.pyスクリプトでは、画像がBGR色空間に読み込まれ、前述の色空間に変換されます。 このスクリプトでは、主要な関数はcv2.cvtColor()で、1つの色空間の入力画像を別の色空間に変換します。

RGB色空間への、またはRGB色空間からの変換の場合、チャネルの順序を明示的に指定する必要があります(BGRまたはRGB)。 例えば:

image = cv2.imread('color_spaces.png')
    

この画像はBGR色空間に読み込まれます。 したがって、それをHSV色空間に変換する場合は、以下を実行する必要があります。

hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    

cv2.COLOR_RGB2HSVではなくcv2.COLOR_BGR2HSVを使用していることに注意してください。

このスクリプトの完全なコードは、color_space.pyにあります。 次のスクリーンショットで出力を確認できます。

前のスクリーンショットに示すように、 BGR画像はHSV、HLS、YCrCb、およびL*a*b*色空間に変換されます。 各色空間のすべてのコンポーネント(チャネル)も表示されます。

color_spaces.py
import cv2
import matplotlib.pyplot as plt
  
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
  
    # Convert BGR image to RGB:
    img_RGB = color_img[:, :, ::-1]
  
    ax = plt.subplot(3, 6, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# Load and display the original image:
image = cv2.imread('color_spaces.png')
  
# create a figure() object with appropriate size and title:
plt.figure(figsize=(12, 5))
plt.suptitle("Color spaces in OpenCV", fontsize=14, fontweight='bold')
  
# Convert to grayscale:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  
# Get the b, g, and r components from the loaded image:
(bgr_b, bgr_g, bgr_r) = cv2.split(image)
  
# Convert to HSV and get the components:
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
(hsv_h, hsv_s, hsv_v) = cv2.split(hsv_image)
  
# Convert to HLS and get the components:
hls_image = cv2.cvtColor(image, cv2.COLOR_BGR2HLS)
(hls_h, hls_l, hls_s) = cv2.split(hls_image)
  
# Convert to YCrCb and get the components:
ycrcb_image = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
(ycrcb_y, ycrcb_cr, ycrcb_cb) = cv2.split(ycrcb_image)
  
# Convert to L*a*b and get the components:
lab_image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
(lab_l, lab_a, lab_b) = cv2.split(lab_image)
  
# Show all the created components:
show_with_matplotlib(image, "BGR - image", 1)
  
# Show gray image:
show_with_matplotlib(cv2.cvtColor(gray_image, cv2.COLOR_GRAY2BGR), "gray image", 1 + 6)
  
# Show bgr components:
show_with_matplotlib(cv2.cvtColor(bgr_b, cv2.COLOR_GRAY2BGR), "BGR - B comp", 2)
show_with_matplotlib(cv2.cvtColor(bgr_g, cv2.COLOR_GRAY2BGR), "BGR - G comp", 2 + 6)
show_with_matplotlib(cv2.cvtColor(bgr_r, cv2.COLOR_GRAY2BGR), "BGR - R comp", 2 + 6 * 2)
   
# Show hsv components:
show_with_matplotlib(cv2.cvtColor(hsv_h, cv2.COLOR_GRAY2BGR), "HSV - H comp", 3)
show_with_matplotlib(cv2.cvtColor(hsv_s, cv2.COLOR_GRAY2BGR), "HSV - S comp", 3 + 6)
show_with_matplotlib(cv2.cvtColor(hsv_v, cv2.COLOR_GRAY2BGR), "HSV - V comp", 3 + 6 * 2)
  
# Show hls components:
show_with_matplotlib(cv2.cvtColor(hls_h, cv2.COLOR_GRAY2BGR), "HLS - H comp", 4)
show_with_matplotlib(cv2.cvtColor(hls_l, cv2.COLOR_GRAY2BGR), "HLS - L comp", 4 + 6)
show_with_matplotlib(cv2.cvtColor(hls_s, cv2.COLOR_GRAY2BGR), "HLS - S comp", 4 + 6 * 2)
   
# Show ycrcb components:
show_with_matplotlib(cv2.cvtColor(ycrcb_y, cv2.COLOR_GRAY2BGR), "YCrCb - Y comp", 5)
show_with_matplotlib(cv2.cvtColor(ycrcb_cr, cv2.COLOR_GRAY2BGR), "YCrCb - Cr comp", 5 + 6)
show_with_matplotlib(cv2.cvtColor(ycrcb_cb, cv2.COLOR_GRAY2BGR), "YCrCb - Cb comp", 5 + 6 * 2)
   
# Show lab components:
show_with_matplotlib(cv2.cvtColor(lab_l, cv2.COLOR_GRAY2BGR), "L*a*b - L comp", 6)
show_with_matplotlib(cv2.cvtColor(lab_a, cv2.COLOR_GRAY2BGR), "L*a*b - a comp", 6 + 6)
show_with_matplotlib(cv2.cvtColor(lab_b, cv2.COLOR_GRAY2BGR), "L*a*b - b comp", 6 + 6 * 2)
   
# Show the created image:
plt.show()
    

Skin segmentation in different color spaces

前述の色空間は、さまざまな画像処理タスクや技法で使用できます。 たとえば、skin_segmentation.pyスクリプトは、さまざまなアルゴリズムを実装して、 さまざまなカラースペース(YCrCb、HSV、RGB)で機能するスキンセグメンテーションを実行します。 このスクリプトは、これらのアルゴリズムがどのように機能するかを確認するために、 いくつかのテスト画像もロードします。

このスクリプトの主要な関数は、すでに説明したcv2.cvtColor()と、 配列に含まれる要素が他の2つの配列の要素の間にあるかどうかを確認するcv2.inRange()です (下限の境界配列と上限境界配列)。

したがって、cv2.inRange()関数を使用して、肌に対応する色をセグメント化します。 ご覧のとおり、これら2つの配列(下限と上限)に定義された値は、 セグメンテーションアルゴリズムのパフォーマンスに重要な役割を果たしています。 このように、適切に設定するために幅広い調査が行われてきました。 この例では、値は次の研究論文から取得されます。

skin_detectorsディクショナリは、 すべてのスキンセグメンテーションアルゴリズムをテスト画像に適用するために構築されています。 printで表示すると、出力は次のようになります。

4つの皮膚検出器が定義されていることがわかります。 スキンセグメンテーション検出器(skin_detector_ycrcbなど)を呼び出すには、以下を実行する必要があります。

detected_skin = skin_detectors['ycrcb'](image)
    

スクリプトの出力は、次のスクリーンショットで確認できます。

複数のテスト画像を使用してさまざまな皮膚セグメンテーションアルゴリズムを適用した効果を確認し、 さまざまな条件下でこれらのアルゴリズムがどのように機能するかを確認できます。

skin_segmentation.py
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
   
# Name and path of the images to load:
image_names = ['test1.jpg', 'test2.jpg', 'test3.jpg', 'test4.jpg', 'test5.jpg', 'test6.jpg']
path = 'skin_test_imgs'
   
# Load all test images building the relative path using 'os.path.join'
def load_all_test_images():
    """Loads all the test images and returns the created array containing the loaded images"""
  
    skin_images = []
    for index_image, name_image in enumerate(image_names):
        # Build the relative path where the current image is:
        image_path = os.path.join(path, name_image)
        # print("image_path: '{}'".format(image_path))
        # Read the image and add it (append) to the structure 'skin_images'
        skin_images.append(cv2.imread(image_path))
    # Return all the loaded test images:
    return skin_images
  
# Show all the images of the array creating the name for each one
def show_images(array_img, title, pos):
    """Shows all the images contained in the array"""
  
    for index_image, image in enumerate(array_img):
        show_with_matplotlib(image, title + "_" + str(index_image + 1), pos + index_image)
  
# Shows the image 'color_img' in the indicated position 'pos'
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
  
    # Convert BGR image to RGB
    img_RGB = color_img[:, :, ::-1]
  
    ax = plt.subplot(5, 6, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# Lower and upper boundaries for the HSV skin segmentation method:
lower_hsv = np.array([0, 48, 80], dtype="uint8")
upper_hsv = np.array([20, 255, 255], dtype="uint8")
  
# Skin detector based on the HSV color space
def skin_detector_hsv(bgr_image):
    """Skin segmentation algorithm based on the HSV color space"""
  
    # Convert image from BGR to HSV color space:
    hsv_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2HSV)
  
    # Find region with skin tone in HSV image:
    skin_region = cv2.inRange(hsv_image, lower_hsv, upper_hsv)
    return skin_region
   
# Lower and upper boundaries for the HSV skin segmentation method:
lower_hsv_2 = np.array([0, 50, 0], dtype="uint8")
upper_hsv_2 = np.array([120, 150, 255], dtype="uint8")
   
# Skin detector based on the HSV color space
def skin_detector_hsv_2(bgr_image):
    """Skin segmentation algorithm based on the HSV color space"""
   
    # Convert image from BGR to HSV color space:
    hsv_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2HSV)
  
    # Find region with skin tone in HSV image:
    skin_region = cv2.inRange(hsv_image, lower_hsv_2, upper_hsv_2)
    return skin_region
  
# Lower and upper boundaries for the YCrCb skin segmentation method:
# Values taken for the publication: 'Face Segmentation Using Skin-Color Map in Videophone Applications'
# The same values appear in the publication 'Skin segmentation using multiple thresholding'
# (Cb in [77, 127]) and (Cr in [133, 173])
lower_ycrcb = np.array([0, 133, 77], dtype="uint8")
upper_ycrcb = np.array([255, 173, 127], dtype="uint8")
   
# Skin detector based on the YCrCb color space
def skin_detector_ycrcb(bgr_image):
    """Skin segmentation algorithm based on the YCrCb color space.
    See 'Face Segmentation Using Skin-Color Map in Videophone Applications'"""
  
    # Convert image from BGR to YCrCb color space:
    ycrcb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2YCR_CB)
  
    # Find region with skin tone in YCrCb image
    skin_region = cv2.inRange(ycrcb_image, lower_ycrcb, upper_ycrcb)
    return skin_region
  
# Values are taken from: 'RGB-H-CbCr Skin Colour Model for Human Face Detection'
# (R > 95) AND (G > 40) AND (B > 20) AND (max{R, G, B} − min{R, G, B} > 15) AND (|R − G| > 15) AND (R > G) AND (R > B)
# (R > 220) AND (G > 210) AND (B > 170) AND (|R − G| ≤ 15) AND (R > B) AND (G > B)
def bgr_skin(b, g, r):
    """Rule for skin pixel segmentation based on the paper 'RGB-H-CbCr Skin Colour Model for Human Face Detection'"""
  
    e1 = bool((r > 95) and (g > 40) and (b > 20) and ((max(r, max(g, b)) - min(r, min(g, b))) > 15) and (
            abs(int(r) - int(g)) > 15) and (r > g) and (r > b))
    e2 = bool((r > 220) and (g > 210) and (b > 170) and (abs(int(r) - int(g)) <= 15) and (r > b) and (g > b))
    return e1 or e2
  
# Skin detector based on the BGR color space
def skin_detector_bgr(bgr_image):
    """Skin segmentation based on the RGB color space"""
  
    h = bgr_image.shape[0]
    w = bgr_image.shape[1]
  
    # We crete the result image with back background
    res = np.zeros((h, w, 1), dtype="uint8")
  
    # Only 'skin pixels' will be set to white (255) in the res image:
    for y in range(0, h):
        for x in range(0, w):
            (b, g, r) = bgr_image[y, x]
            if bgr_skin(b, g, r):
                res[y, x] = 255
  
    return res
  
# Implemented skin detectors to be used:
skin_detectors = {
    'ycrcb': skin_detector_ycrcb,
    'hsv': skin_detector_hsv,
    'hsv_2': skin_detector_hsv_2,
    'bgr': skin_detector_bgr
}
    
# Apply the 'skin_detector' to all the images in the array
def apply_skin_detector(array_img, skin_detector):
    """Applies the specific 'skin_detector' to all the images in the array"""
  
    skin_detector_result = []
    for index_image, image in enumerate(array_img):
        detected_skin = skin_detectors[skin_detector](image)
        bgr = cv2.cvtColor(detected_skin, cv2.COLOR_GRAY2BGR)
        skin_detector_result.append(bgr)
    return skin_detector_result
  
# create a figure() object with appropriate size and set title:
plt.figure(figsize=(15, 8))
plt.suptitle("Skin segmentation using different color spaces", fontsize=14, fontweight='bold')
  
# Show the skin_detectors dictionary
# This is only for debugging purposes
for i, (k, v) in enumerate(skin_detectors.items()):
    print("index: '{}', key: '{}', value: '{}'".format(i, k, v))
  
# We load all the test images:
test_images = load_all_test_images()
   
# We plot the test images:
show_images(test_images, "test img", 1)
   
# For each skin detector we apply and show all the test images:
show_images(apply_skin_detector(test_images, 'ycrcb'), "ycrcb", 7)
show_images(apply_skin_detector(test_images, 'hsv'), "hsv", 13)
show_images(apply_skin_detector(test_images, 'hsv_2'), "hsv_2", 19)
show_images(apply_skin_detector(test_images, 'bgr'), "bgr", 25)
   
# Show the created image:
plt.show()
    

Color maps

多くのコンピュータビジョンアプリケーションでは、アルゴリズムの出力はグレースケールイメージです。 しかし、人間の目はグレースケール画像の変化を観察するのが得意ではありません。 カラー画像の変化を認識するとき、それらはより敏感なので、 一般的なアプローチは、グレースケール画像を疑似色の同等の画像に変換(色変更)することです。

Color maps in OpenCV

この変換を実行するために、OpenCVには視覚化を強化するいくつかのカラーマップがあります。 cv2.applyColorMap()関数は、指定された画像にカラーマップを適用します。 次のコードに示すように、color_map_example.pyスクリプトはグレースケールイメージを読み込み、 cv2.COLORMAP_HSVカラーマップを適用します。

img_COLORMAP_HSV = cv2.applyColorMap(gray_img, cv2.COLORMAP_HSV)
    

最後に、すべてのカラーマップを同じグレースケールイメージに適用し、同じ図にプロットします。 これは、color_map_all.pyスクリプトで確認できます。 OpenCVが定義したカラーマップは次のとおりです。

color_map_all.pyスクリプトは、これらすべてのカラーマップをグレースケールイメージに適用します。 このスクリプトの出力は、次のスクリーンショットで確認できます。

前のスクリーンショットでは、視覚化を強化する目的で、 すべての定義済みカラーマップをグレースケールイメージに適用した効果を確認できます。

color_map_example.py
import cv2
import matplotlib.pyplot as plt
   
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
    
    # Convert BGR image to RGB
    img_RGB = color_img[:, :, ::-1]
   
    # Add the subplot to the created figure
    ax = plt.subplot(1, 2, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# We create a figure() object with appropriate size and title:
plt.figure(figsize=(8, 4))
plt.suptitle("Colormaps", fontsize=14, fontweight='bold')
  
# We load the image using cv2.imread() and using 'cv2.IMREAD_GRAYSCALE' argument:
gray_img = cv2.imread('lenna.png', cv2.IMREAD_GRAYSCALE)
  
# We apply the color map 'cv2.COLORMAP_HSV'
img_COLORMAP_HSV = cv2.applyColorMap(gray_img, cv2.COLORMAP_HSV)
  
# Add the subplot:
show_with_matplotlib(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR), "gray image", 1)
show_with_matplotlib(img_COLORMAP_HSV, "HSV", 2)
  
# Show the created image:
plt.show()
    

Custom color maps

カスタムカラーマップを画像に適用することもできます。 この機能は、いくつかの方法で実現できます。

最初のアプローチは、0〜255のグレースケール値を256色にマップするカラーマップを定義することです。 これは、作成されたすべての色を保存するために、サイズ256 x 1の8ビットのカラー画像を作成することで実行できます。 その後、ルックアップテーブルを使用して、イメージのグレースケール強度を定義済みの色にマッピングします。 これを実現するには、次のいずれかを実行します。

重要なポイントの1つは、サイズ256x1の8ビットカラーイメージを作成するときに、 作成したカラーを保存することです。cv2.LUT()を使用する場合、イメージは次のように作成する必要があります。

lut = np.zeros((256, 3), dtype=np.uint8)
    

cv2.applyColorMap()を使用する場合は、次のようにする必要があります。

lut = np.zeros((256, 1, 3), dtype=np.uint8)
    

このための完全なコードは、color_map_custom_values.pyで確認できます。 このスクリプトの出力は、次のスクリーンショットで確認できます。

color_map_custom_values.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
  
def apply_custom_colormap_values(im_gray):
    """Applies a custom color map using cv2.applyColorMap()"""
  
    # Create the LUT:
    lut = np.zeros((256, 1, 3), dtype=np.uint8)
    lut[:, 0, 0] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255, 255, 255, 255, 253, 251, 249, 247, 245, 242, 241, 238, 237, 235, 233, 231, 229, 227, 225,
                    223, 221, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185,
                    183, 181, 179, 177, 175, 173, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151, 149, 147, 145,
                    143, 141, 138, 136, 134, 132, 131, 129, 126, 125, 122, 121, 118, 116, 115, 113, 111, 109, 107, 105,
                    102, 100, 98, 97, 94, 93, 91, 89, 87, 84, 83, 81, 79, 77, 75, 73, 70, 68, 66, 64, 63, 61, 59, 57,
                    54, 52, 51, 49, 47, 44, 42, 40, 39, 37, 34, 33, 31, 29, 27, 25, 22, 20, 18, 17, 14, 13, 11, 9, 6, 4,
                    2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
  
    lut[:, 0, 1] = [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                    200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 198, 196, 194, 192,
                    190, 188, 186, 184, 182, 180, 178, 176, 174, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151,
                    149, 147, 145, 143, 141, 139, 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111,
                    109, 107, 105, 103, 101, 99, 97, 95, 93, 91, 89, 87, 85, 83, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64,
                    62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14,
                    12, 10, 8, 6, 4, 2, 0]
  
    lut[:, 0, 2] = [195, 194, 193, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 174,
                    173, 172, 171, 170, 169, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 155, 154, 153, 152,
                    151, 150, 149, 148, 147, 146, 145, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 131, 130,
                    129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110,
                    109, 108, 107, 106, 105, 104, 103, 102, 101, 95, 99, 98, 97, 96, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                    95, 95, 95]
  
    # Apply color map using cv2.applyColorMap()
    im_color = cv2.applyColorMap(im_gray, lut)
    return im_color
   
def apply_custom_colormap_values2(im_gray):
    """Applies a custom color map using cv2.LUT()"""
  
    # Create the LUT:
    lut = np.zeros((256, 3), dtype=np.uint8)
    lut[:, 0] = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                 255, 255, 255, 255, 255, 253, 251, 249, 247, 245, 242, 241, 238, 237, 235, 233, 231, 229, 227, 225,
                 223, 221, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185,
                 183, 181, 179, 177, 175, 173, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151, 149, 147, 145,
                 143, 141, 138, 136, 134, 132, 131, 129, 126, 125, 122, 121, 118, 116, 115, 113, 111, 109, 107, 105,
                 102, 100, 98, 97, 94, 93, 91, 89, 87, 84, 83, 81, 79, 77, 75, 73, 70, 68, 66, 64, 63, 61, 59, 57,
                 54, 52, 51, 49, 47, 44, 42, 40, 39, 37, 34, 33, 31, 29, 27, 25, 22, 20, 18, 17, 14, 13, 11, 9, 6, 4,
                 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
   
    lut[:, 1] = [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
                 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 198, 196, 194, 192,
                 190, 188, 186, 184, 182, 180, 178, 176, 174, 171, 169, 167, 165, 163, 161, 159, 157, 155, 153, 151,
                 149, 147, 145, 143, 141, 139, 137, 135, 133, 131, 129, 127, 125, 123, 121, 119, 117, 115, 113, 111,
                 109, 107, 105, 103, 101, 99, 97, 95, 93, 91, 89, 87, 85, 83, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64,
                 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14,
                 12, 10, 8, 6, 4, 2, 0]
  
    lut[:, 2] = [195, 194, 193, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 174,
                 173, 172, 171, 170, 169, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 155, 154, 153, 152,
                 151, 150, 149, 148, 147, 146, 145, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 131, 130,
                 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110,
                 109, 108, 107, 106, 105, 104, 103, 102, 101, 95, 99, 98, 97, 96, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
                 95, 95, 95]
  
    # Apply color map using cv2.LUT():
    s0, s1 = im_gray.shape
    im_color = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
  
    for i in range(3):
        im_color[..., i] = cv2.LUT(im_gray, lut[:, i])
    return im_color
  
def apply_rand_custom_colormap_values(im_gray):
    """Applies a random color map using cv2.applyColorMap()"""
  
    # Create random LUT
    lut = np.random.randint(255, size=(256, 1, 3), dtype=np.uint8)
  
    # Apply color map using cv2.applyColorMap()
    im_color = cv2.applyColorMap(im_gray, lut)
    return im_color
  
def apply_rand_custom_colormap_values2(im_gray):
    """Applies a random color map using cv2.LUT()"""
  
    # Create random LUT
    lut = np.random.randint(255, size=(256, 3), dtype=np.uint8)
  
    # Apply color map using cv2.LUT():
    s0, s1 = im_gray.shape
    im_color = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
    for i in range(3):
        im_color[..., i] = cv2.LUT(im_gray, lut[:, i])
    return im_color
  
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
  
    # Convert BGR image to RGB
    img_RGB = color_img[:, :, ::-1]
  
    ax = plt.subplot(1, 5, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# We load the image using cv2.imread() and using 'cv2.IMREAD_GRAYSCALE' argument:
gray_img = cv2.imread('shades.png', cv2.IMREAD_GRAYSCALE)
  
# create a figure() object with appropriate size and title:
plt.figure(figsize=(12, 2))
plt.suptitle("Custom colormaps providing all values", fontsize=14, fontweight='bold')
   
# Show image:
show_with_matplotlib(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR), "gray", 1)
   
# Apply the custom color maps to the grayscale image:
custom_rand_1 = apply_rand_custom_colormap_values(gray_img)
custom_rand_2 = apply_rand_custom_colormap_values2(gray_img)
custom_values_1 = apply_custom_colormap_values(gray_img)
custom_values_2 = apply_custom_colormap_values2(gray_img)
  
# Display all the resulting images:
show_with_matplotlib(custom_rand_1, "cv2.applyColorMap()", 2)
show_with_matplotlib(custom_rand_2, "cv2.LUT()", 3)
show_with_matplotlib(custom_values_1, "cv2.applyColorMap()", 4)
show_with_matplotlib(custom_values_2, "cv2.LUT()", 5)
  
# Show the created image:
plt.show()
    

カラーマップを定義する2番目のアプローチは、一部のキーカラーのみを提供し、値を補間して、 必要なすべてのカラーを取得してルックアップテーブルを作成することです。 color_map_custom_key_colors.pyスクリプトは、これを実現する方法を示しています。

build_lut()関数は、これらのキーカラーに基づいてルックアップテーブルを作成します。 5つのカラーポイントに基づいて、この関数はnp.linespace()を呼び出し、 間隔ごとに計算された64の等間隔カラーをすべて取得します。 各カラーは2つのカラーポイントで定義されます。 これをよりよく理解するには、次のスクリーンショットを見てください。

このスクリーンショットでは、たとえば、 2つの線分セグメントの64の等間隔に配置されたすべての色を計算する方法を確認できます (緑と青の強調表示されたセグメントを参照)。

最後に、次の5つの主要なカラーポイント ((0,(0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)), (0.75, (64, 128, 224)), および(1.0, (0, 128,255)))では、np.linespace()への次の呼び出しが実行されます。

color_map_custom_key_colors.pyスクリプトの出力は、次のスクリーンショットで確認できます。

前のスクリーンショットでは、2つのカスタムカラーマップをグレースケールイメージに適用した効果を確認できます。

color_map_custom_key_colors.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
   
# This dictionary is only for debugging purposes:
dict_color = {0: "blue", 1: "green", 2: "red"}
   
def build_lut(cmap):
    """Builds look up table based on 'key colors' using np.linspace()"""
  
    lut = np.empty(shape=(256, 3), dtype=np.uint8)
    # Show for debugging purposes:
    print("----------")
    print(cmap)
    print("-----")
  
    max = 256
    # build lookup table:
    lastval, lastcol = cmap[0]
    for step, col in cmap[1:]:
        val = int(step * max)
        for i in range(3):
            print("{} : np.linspace('{}', '{}', '{}' - '{}' = '{}')".format(dict_color[i], lastcol[i], col[i], val,
                                                                            lastval, val - lastval))
            lut[lastval:val, i] = np.linspace(lastcol[i], col[i], val - lastval)
  
        lastcol = col
        lastval = val
  
    return lut
  
def apply_color_map_1(gray, cmap):
    """Applies a custom color map using cv2.LUT()"""
  
    lut = build_lut(cmap)
    s0, s1 = gray.shape
    out = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
  
    for i in range(3):
        out[..., i] = cv2.LUT(gray, lut[:, i])
    return out
  
def apply_color_map_2(gray, cmap):
    """Applies a custom color map using cv2.applyColorMap()"""
  
    lut = build_lut(cmap)
    lut_reshape = np.reshape(lut, (256, 1, 3))
    im_color = cv2.applyColorMap(gray, lut_reshape)
    return im_color
  
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
  
    # Convert BGR image to RGB
    img_RGB = color_img[:, :, ::-1]
  
    ax = plt.subplot(2, 3, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# Read grayscale image:
gray_img = cv2.imread('shades.png', cv2.IMREAD_GRAYSCALE)
  
# Create the dimensions of the figure and set title:
plt.figure(figsize=(14, 3))
plt.suptitle("Custom color maps based on key colors", fontsize=14, fontweight='bold')
  
# Show gray image:
show_with_matplotlib(cv2.cvtColor(gray_img, cv2.COLOR_GRAY2BGR), "gray", 1)
   
# Apply the custom color map - (b,g,r) values:
custom_1 = apply_color_map_1(gray_img, ((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
                                        (0.75, (255, 0, 60)), (1.0, (255, 0, 0))))
   
custom_2 = apply_color_map_1(gray_img, ((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
                                        (0.75, (64, 128, 224)), (1.0, (0, 128, 255))))
  
custom_3 = apply_color_map_2(gray_img, ((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
                                        (0.75, (255, 0, 60)), (1.0, (255, 0, 0))))
  
custom_4 = apply_color_map_2(gray_img, ((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
                                        (0.75, (64, 128, 224)), (1.0, (0, 128, 255))))
   
# Display all the resulting images:
show_with_matplotlib(custom_1, "custom 1 using cv2.LUT()", 2)
show_with_matplotlib(custom_2, "custom 2 using cv2.LUT()", 3)
show_with_matplotlib(custom_3, "custom 3 using cv2.applyColorMap()", 5)
show_with_matplotlib(custom_4, "custom 4 using using cv2.applyColorMap()", 6)
   
# Show the Figure:
plt.show()
    

Showing the legend for the custom color map

最後に、興味深い機能の1つは、カスタムカラーマップを表示するときに凡例を提供することです。 これは、color_map_custom_legend.pyスクリプトで実現できます。

凡例画像を作成するために、build_lut_image()関数がこの機能を実行します。 まず、ルックアップテーブルを取得するために、build_lut()関数を呼び出します。 次に、このルックアップテーブルを数回複製するためにnp.repeat()を呼び出します (この操作はheight回繰り返されます)。 ルックアップテーブルの形状は(256,3)であることに注意してください。 出力画像の形状を(256, 3)にしたいので、 次のようにnp.repeat()をnp.newaxis()と一緒に使用できます。

image = np.repeat(lut[np.newaxis, ...], height, axis=0)
    

このスクリプトの出力は、次のスクリーンショットで確認できます。

上のスクリーンショットでは、2つのカスタムカラーマップをグレースケールイメージに適用した効果と、 各カラーマップの凡例を示しています。

color_map_custom_legend.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
   
def build_lut_image(cmap, height):
    """Builds the legend image"""
   
    lut = build_lut(cmap)
    image = np.repeat(lut[np.newaxis, ...], height, axis=0)
   
    return image
   
def build_lut(cmap):
    """Builds look up table based on 'key colors' using np.linspace()"""
  
    lut = np.empty(shape=(256, 3), dtype=np.uint8)
    max = 256
    # build lookup table:
    lastval, lastcol = cmap[0]
    for step, col in cmap[1:]:
        val = int(step * max)
        for i in range(3):
            lut[lastval:val, i] = np.linspace(lastcol[i], col[i], val - lastval)
   
        lastcol = col
        lastval = val
  
    return lut
  
def apply_color_map_1(gray, cmap):
    """Applies a custom color map using cv2.LUT()"""
  
    lut = build_lut(cmap)
    s0, s1 = gray.shape
    out = np.empty(shape=(s0, s1, 3), dtype=np.uint8)
  
    for i in range(3):
        out[..., i] = cv2.LUT(gray, lut[:, i])
    return out
  
def apply_color_map_2(gray, cmap):
    """Applies a custom color map using cv2.applyColorMap()"""
  
    lut = build_lut(cmap)
    lut2 = np.reshape(lut, (256, 1, 3))
    im_color = cv2.applyColorMap(gray, lut2)
    return im_color
  
def show_with_matplotlib(color_img, title, pos):
    """Shows an image using matplotlib capabilities"""
  
    # Convert BGR image to RGB
    img_RGB = color_img[:, :, ::-1]
  
    ax = plt.subplot(2, 2, pos)
    plt.imshow(img_RGB)
    plt.title(title)
    plt.axis('off')
  
# Read grayscale image:
gray_img = cv2.imread('lenna.png', cv2.IMREAD_GRAYSCALE)
  
# Create the dimensions of the figure and set title:
plt.figure(figsize=(14, 6))
plt.suptitle("Custom color maps based on key colors and legend", fontsize=14, fontweight='bold')
   
# Build the color maps (b,g,r) values:
custom_1 = apply_color_map_1(gray_img, ((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
                                        (0.75, (255, 0, 60)), (1.0, (255, 0, 0))))
  
custom_2 = apply_color_map_2(gray_img, ((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
                                        (0.75, (64, 128, 224)), (1.0, (0, 128, 255))))
  
# Build the legend images:
legend_1 = build_lut_image(((0, (255, 0, 255)), (0.25, (255, 0, 180)), (0.5, (255, 0, 120)),
                            (0.75, (255, 0, 60)), (1.0, (255, 0, 0))), 20)
  
legend_2 = build_lut_image(((0, (0, 255, 128)), (0.25, (128, 184, 64)), (0.5, (255, 128, 0)),
                            (0.75, (64, 128, 224)), (1.0, (0, 128, 255))), 20)
   
# Display all the resulting images:
show_with_matplotlib(legend_1, "", 1)
show_with_matplotlib(custom_1, "", 3)
show_with_matplotlib(legend_2, "", 2)
show_with_matplotlib(custom_2, "", 4)
  
# Show the Figure:
plt.show()
    

Summary

この章では、コンピュータービジョンプロジェクトに必要な一般的な画像処理技術のほとんどを確認しました。 次の3つの章(第6章、ヒストグラムの作成と構築、第7章、しきい値処理手法、および第8章、輪郭検出、フィルタリング、および描画)では、 最も一般的な画像処理手法について説明します。

第6章「ヒストグラムの作成と構築」では、ヒストグラムを作成および理解する方法について学習します。 ヒストグラムは、画像コンテンツをよりよく理解するために使用される強力な手法です。