OpenCV クイック スタート 5: 色空間変換

1: 関連する API

1:イムリード

imread(filename, cv.IMREAD_GRAYSCALE)

特定の cv.imread とその使用方法、および中国語のパスで画像を読み取る方法については、ブログ「OpenCV Learning one: Picture reading & Saving」を参照してください。

2:CVTカラー

cvtColor(	src,           #输入
			code[,         #色彩空间转换的代码或表示.
			dst=None[,     #输出
			dstCn=None]]#目标图像通道数
)

3getTrackbarPos

getTrackbarPos(滑动条名字,窗口名,输出当前值)

この関数は、入力画像をある色空間から別の色空間に変換します。RGB 色空間から変換する場合、チャンネル (RGB または BGR) の順序を明示的に指定する必要があります。OpenCV のデフォルトのカラー形式は RGB と呼ばれることが多いですが、実際には BGR (Byte Reversed) であることに注意してください。したがって、標準 (24 ビット) カラー画像の最初のバイトは 8 ビットの青コンポーネント、2 番目のバイトは緑、3 番目のバイトは赤になります。次に、4、5、6 バイトが 2 番目のピクセル (青、緑、赤) になります。
R、G、B チャネル値の通常の範囲は次のとおりです:
CV_8U イメージの場合は 0 ~ 255 CV_16U イメージ
の場合は 0 ~ 65535
CV_32F イメージの場合は 0 ~ 1

線形変換の場合、範囲は重要ではありません。ただし、非線形変換の場合、正しい結果を得るには、入力 RGB 画像を適切な値範囲に正規化する必要があります。たとえば、スケーリングなしで 8 ビット イメージから直接変換された 32 ビット浮動小数点イメージがある場合、その値の範囲は関数が想定している 0 ~ 1 ではなく、0 ~ 255 になります。したがって、 cvtColor を呼び出す前に、まず画像を縮小する必要があります。

img *= 1./255;
cvtColor(img, img, COLOR_BGR2Luv); 8 ビット画像に
cvtColor 変換を使用すると、一部の情報が失われます。
多くのアプリケーションではこれは目立ちませんが、全範囲の色を必要とするアプリケーションや、画像を操作前に変換してから再度元に戻すアプリケーションには 32 ビット画像をお勧めします。
変換によってアルファ チャネルが追加される場合、その値は対応するチャネル範囲の最大値に設定されます。CV_8U の場合は 255、CV_16U の場合は 65535、CV_32F の場合は 1 です。

2: コードのデモンストレーション

import cv2
import numpy as np

def callback(userdata):
    pass

cv2.namedWindow('color', cv2.WINDOW_NORMAL)
img = cv2.imdecode(np.fromfile(r"C:\Users\DMr\Pictures\个人\xiaoqi.jpg",dtype=np.uint8),1)


colorspaces = [cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA,
               cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV,
               cv2.COLOR_BGR2YUV]
cv2.createTrackbar('curcolor', 'color', 0, 4, callback)

while True:
    index = cv2.getTrackbarPos('curcolor', 'color')

    #颜色空间转换API
    cvt_img = cv2.cvtColor(img, colorspaces[index])

    cv2.imshow('color', cvt_img)
    key = cv2.waitKey(10)
    if key & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

出力
ここに画像の説明を挿入

3: 一般的な色の種類

RGB: 人間の目の色空間
BGR: OpenCV、Windows
HSV/HSB - 色とは何か、色の深さ、色の明るさはどれくらい
YUV 色空間 - ビデオ
ある
ここに画像の説明を挿入します
ここにASF画像の説明を挿入

1: RGB の制限

RGB は私たちが最もよく目にする色空間であり、画像は赤®、緑 (G)、青 (B) の 3 つのチャネルで表されます。これら 3 つの色のさまざまな組み合わせにより、他のほぼすべての色を形成できます。

RGB 色空間は、画像処理において最も基本的で最も一般的に使用されるハードウェア指向の色空間であり、比較的理解しやすいものです。

RGB 色空間では、3 つの色成分の線形結合を使用して色を表現します。どの色もこれら 3 つの成分に関連しており、これら 3 つの成分は高度に相関しているため、色を継続的に変更するのは直感的ではありません。調整にはこれら 3 つの成分を変更する必要があります。 。

自然環境で取得された画像は、自然光、遮蔽、影の影響を受けやすく、明るさに敏感です。RGB 色空間の 3 つの成分は明るさと密接に関係しています。つまり、明るさが変化すると、3 つの成分もそれに応じて変化するため、これほど直感的に表現できる方法はありません。

しかし、これら3つの色成分に対する人間の目の感度は異なり、モノクロでは人間の目は赤に対して最も感度が低く、青に対して最も感度が高いため、RGB色空間は均一性の悪い色空間である。色の類似性をユークリッド距離で直接測定すると、人間の視覚とは大きく乖離した結果が得られます。特定の色について、より正確な 3 成分の数値表現を推測することは困難です。

したがって、RGB 色空間は表示システムには適していますが、画像処理には適していません。

2: HSV色空間

上記の理由に基づいて、RGB よりも人間の色の知覚経験に近い HSV 色空間が画像処理でよく使用されます。色の色合い、鮮やかさ、明度を直感的に表現できるので、色の比較に便利です。

HSV 色空間では、BGR よりも特定の色のオブジェクトを追跡するのが容易であり、指定された色のオブジェクトをセグメント化するためによく使用されます。

HSV がカラー画像を表現する方法は、次の 3 つの部分で構成されます。

  • 色相(色相、色相) 0~360は通常赤と緑と呼ばれるもので、さらに細かく分けるとマゼンタ、グラスグリーンなどがあり、HSVモデルでは色相を度数で表現し、赤を表現します。は 0 度、緑は 120 度、青は 240 度に対応します。

  • 彩度(彩度、色純度) 0~255 色の濃さ(0~100%)、赤などの色の場合、薄赤~明るい赤~濃い赤~紫赤などを使用できます。言葉で言えば(純粋な科学の学生の色彩システムの欠如を許してください)、それは水彩画を描くとき、​​つまり、1種類の顔料に異なる量の水を加えて異なる彩度を形成することに相当します。

  • 値 (明るさ) 0 ~ 255 これは、画面の明るさを調整する場合によく使用されます。

HSV 色空間を表すには次の円柱を使用します。円柱の断面は極座標系とみなすことができます。H は極座標の極角で表され、S は極座標の極軸長で表されます、V は円柱の軸で表されます。
ここに画像の説明を挿入

色相は角度によって測定され、値の範囲は 0 ~ 360°で、色情報、つまり分光色の位置を表します。これは次のように表されます。
ここに画像の説明を挿入
色相環上のすべての色は赤から始まり反時計回りに回転するスペクトル上の色であり、色相 = 0 は赤、色相 = 120 は緑、色相 = 240 は青などを意味します。

RGB では、色は 3 つの値によって決まります。たとえば、黄色は (255,255,0) ですが、HSV では、黄色は 1 つの値 (Hue=60) だけで決まります。

HSV 円柱の半側断面図 (色相 = 60):
ここに画像の説明を挿入

横方向は彩度を表し、彩度は分光色にどの程度近いかを表します。彩度が高いほど色は暗くなり、分光色に近づき、彩度が低いほど色は明るくなり、白に近づきます。彩度 0 は純粋な白を意味します。値の範囲は 0 ~ 100% で、値が大きいほど、色の彩度が高くなります。

縦方向は明度を表し、色空間における色の明暗を決定し、明度が高いほど色が明るくなり、範囲は 0 ~ 100% です。明度 0 は純粋な黒 (この時点で最も暗い色) を意味します。
S=1 V=1 のとき、H で表される色は純色と呼ばれ、
S=0、つまり彩度が 0 のとき、その色が最も明るく、最も明るい色はグレーと表現されます (グレーには明度もあります) 、黒と白もグレーに属します)、グレーの明るさは V によって決まり、このとき H は意味がありません;
V=0 のとき、色が最も暗く、最も暗いものは黒と表現されます。 H(どんな色でも一番暗いのは黒)とS(どんな色でも一番暗いのは黒)は意味がありません。

それは次のように理解できます。

特定の色相の場合、彩度が減少、つまり分光色に白が追加され、分光色の割合も減少し、彩度が​​ 0 に減少します。 color が 0 の場合、全体の色が白く表示されます。

明度が下がると分光色に黒が加わり、分光色の割合も減り、明度が0になると分光色の割合がゼロとなり、全体の色が見えるようになります。黒。

HSV は、ユーザーにとってより直感的なカラー モデルです。単一の色を簡単に取得できます。つまり、色の角度 H を指定し、V=S=1 とし、それに黒と白を追加することで必要な色を取得できます。黒を増やすと S は変化せずに V が減少し、白を増やすと V は変化せずに S が減少します。たとえば、濃い青を得るには、V=0.4 S=1 H=240 度です。水色を取得するには、V=1 S=0.4 H=240 度です。

HSV のストレッチ コントラスト強調は、S と V の 2 つのコンポーネントを正規化することであり (最小-最大正規化)、H は変更されません。

RGB カラー スペースはより業界指向であるのに対し、HSV はよりユーザー指向です。HSV カラー スペースはより直感的に表現できるため、画像認識を行うほとんどの人は HSV カラー スペースを使用します。

RGB➡HSV

  1. V = max(R, G, B)/255.0f - 明るさ V は、正規化する RGB 値の最大値です。
    推論: 純粋な色の RGB の 1 つは 255 でなければなりません。同時に、3 つの 255 RGB 値を持つことは不可能です。3 つの 255 は白であり、白は、どの色 H についても V=1 および S=0 のときの積です。また、V=1 S=0 は純粋な色ではありません。同時に、V=0の場合、RGBの最大値は0、すなわちGRBは0となり、画素が黒であることを意味する。
  2. S = (max(R, G, B) - min(R, G, B))/(float)max(R, G, B) - 彩度 S は、RGB と最小値の差です。最大値の比率。
    推論:
    S=1 の場合、max(R, G, B) - min(R, G, B) == m であるため、純粋な色の RGB 値 (S=1 V=1) には 0 が存在する必要があります。 ax(R, G, B)、つまり RGBMin =0。これは白も考慮します (RGB(255,255,255) は純粋な色ではありません)。
    S = 0、RGBMax-RGBMin == 0、つまり R の場合GB. このとき、色はさまざまな程度のグレーです (白から黒まで、明るさは V によって決まります。V=RGBMax*100/255 であるため、V が高くなるほど、RGBMax が高くなります)。RG==B が高いほど、グレーは明るくなります))。これは、上記のヒストグラムからもわかります。
    したがって、純粋な色には、RGB に 255 と 0 がなければなりません。
    数式変換:ここに画像の説明を挿入します

HSV➡RGB

ここに画像を挿入します。画像の説明

3:HSL

ここに画像を挿入します 画像の説明
HSLとHSVは似ているので、ここでまとめて紹介します。HLS には、色相 (色相)、彩度 (彩度)、明度 (明るさ) という 3 つのコンポーネントもあります。

HSL と HSV の違いは、最後のコンポーネントが異なることです。HLS はライト (明るさ)、HSV は値 (明るさ) です。このページで試してみることができます

HSL の L コンポーネントは明度です。明度が 100 の場合は白を意味し、明度が 0 の場合は黒を意味します。

以下は HSL カラー空間シリンダーです。
ここに画像の説明を挿入
白いオブジェクトを抽出する場合、HLS を使用する方が便利です。HSV には色相に白がなく、白は S と V によって決定される必要があるためです (S=0、V=100)。 )。HLS では、白は明るさの L 成分によってのみ決定されます。したがって、白を検出する場合は HSL 色空間を使用する方がより正確です。

テストには上記の HSL 色空間図を使用します。

img = cv2.imread("hls.jpg")

# Convert BGR to HLS
imgHLS = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)

# range of white color in L channel
# mask = cv2.inRange(imgHLS[:,:,1], lowerb=250, upperb=255)
mask = cv2.inRange(imgHLS, np.array([0,250,0]), np.array([255,255,255]))

# Apply Mask to original image
white_mask = cv2.bitwise_and(img, img, mask=mask)

出力
ここに画像の説明を挿入

注: OpenCV の HLS の 3 つのコンポーネントの範囲は次のとおりです:
H = [0,179]
L = [0,255]
S = [0,255]

注: OpenCV における HSV の 3 つのコンポーネントの範囲は次のとおりです:
H = [0,180]
S = [0,255]
V = [0,255]

追跡するオブジェクトの色の HSV 値を取得します。

BGR 値に対して色空間変換を実行して、HSV 値を取得します。

 blue = np.uint8([[[255,0,0]]])
 hsv_blue = cv2.cvtColor(blue, cv2.COLOR_BGR2HSV)
 print(hsv_blue)  #[[[120 255 255]]]

特定の色のオブジェクトを識別するには、その色に対応する HSV 値を取得することが非常に重要です。取得手順は次のとおりです。

1.オンライン カラー ピッカーまたは画像認識。ここで特定の色の画像をアップロードし、これらの色に対応する RGB 値を取得できます。

2. 取得したデータが #869C90、#899F92、#8A9E92、#8A9F8E であると仮定し、これを変換して HSV の各チャネルの値の範囲を取得します。

rgb = '#869C90,#899F92,#8A9E92,#8A9F8E'

rgb = rgb.split(',')

# 转换为BGR格式,并将16进制转换为10进制
bgr = [[int(r[5:7], 16), int(r[3:5], 16), int(r[1:3], 16)] for r in rgb]

# 转换为HSV格式
hsv = [list(cv2.cvtColor(np.uint8([[b]]), cv2.COLOR_BGR2HSV)[0][0]) for b in bgr]

hsv = np.array(hsv)
print('H:', min(hsv[:, 0]), max(hsv[:, 0]))
print('S:', min(hsv[:, 1]), max(hsv[:, 1]))
print('V:', min(hsv[:, 2]), max(hsv[:, 2]))

次に、色相の値に 10 を加算して 10 を減算し (ここで、10 は特定の状況に応じて他の値にすることもできます)、色相の範囲を取得し、S と V の範囲 (色相の上限と最終値) を指定します。 HSV全体ここに画像の説明を挿入
下限値は[hue+10, 100, 100]と[hue-10, 255, 255]で、SとVの下限値は状況に応じて設定できます。

H=0 と H=180 はどちらも赤に対応するため、赤の場合は 2 つの範囲を定義し、OR 演算を実行する必要があります。

sensitivity = 10
lower_red_0 = np.array([0,100,100]) 
upper_red_0 = np.array([sensitivity,255,255])
lower_red_1 = np.array([180-sensitivity,100,100]) 
upper_red_1 = np.array([180,255,255])

mask_0 = cv2.inRange(hsv, lower_red_0, upper_red_0)
mask_1 = cv2.inRange(hsv, lower_red_1, upper_red_1)

mask = cv2.bitwise_or(mask_0, mask_1)

カラーベースのしきい値処理には cv2:inRange() を使用します。

その後、HSV 値の範囲を使用してターゲット オブジェクトを抽出できます。

import cv2
import numpy as np
#cam = cv2.VideoCapture(0)
img = cv2.imread('C:\\Users\\DMr\\Pictures\\text\\phone.jpg', cv2.IMREAD_COLOR)
cv2.imshow("yuantu",img)
Obj_low = np.array([0,0,0])#找到对应对象的HSV颜色
Obj_high = np.array([179,157,79])
while True:
    #img = cam.read()[1]
    img = cv2.resize(img, (800,600) )
    blur_img = cv2.GaussianBlur(img,(23,23),0)#使用高斯滤波器对图像进行归一化
    cv2.imshow("ga", blur_img)
    HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)#将图像转换为HSV颜色模型
    cv2.imshow("hsv", HSV)
    MASK1 = cv2.inRange(HSV, Obj_low, Obj_high)#在给定的HSV值范围内应用二进制阈值,黑白Obj_low和Obj_high。
    #MASK2 = cv2.inRange(HSV,Obj2_low,Obj2_high) #如果尝试跟踪两个不同的对象,则需要创建2个不同的蒙版,并最终在两个蒙版上使用“按位与”运算符。
    #mask = cv2.bitwise_and(mask1,mask2)
    MASK1 = cv2.erode(MASK1, None, iterations=2)#侵蚀和膨胀:侵蚀和膨胀填充阈值图像中的黑色和白色斑点。这样可使图像更清晰,平滑并突出主要对象
    MASK1 = cv2.dilate(MASK1, None, iterations =2)
    cv2.imshow("fushi",MASK1)
    cnts = cv2.findContours(MASK1.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
    center = None#轮廓:突出显示对象的图像片段。例如,如果将二进制阈值应用于具有(180,255)的图像,则大于180
              # 的像素将以白色突出显示,而其他则为黑色。白色部分称为轮廓。

    if len(cnts)>0 :
        c = max(cnts, key = cv2.contourArea)#在上面给定的图像中,整个白色边界区域是轮廓。轮廓可能不止一个,但主要对象的面积将最大。所以选择轮廓最大

        ((x,y), radius) = cv2.minEnclosingCircle(c)#得到主要物体的轮廓后,在轮廓上画一个圆
        M = cv2.moments(c)
        center = (int(M['m10']/ M['m00']), int(M['m01']/ M['m00']) )
        if radius>10:
            cv2.circle(img, center, 5, (0,0,255), -1)
            cv2.circle(img, center, int(radius), (0,0,255), 2)

    cv2.imshow("my window",img)
    k = cv2.waitKey(1)
    if k==27:
        break
img.release()
#cam.release()
cv2.destroyAllWindows()

HSL チャネルの分離については、前の記事を参照してください

Daily "Big Pie":
運命は沈んだ流れと無常のようなものであり、それを止めるのは難しいでしょう

おすすめ

転載: blog.csdn.net/weixin_52051554/article/details/126019194