OpenCV 的 cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 會回傳 HSV 陣列,其中色相範圍為 0 到 179,飽和度範圍為 0 到 255,明度範圍為 0 到 255 — 這是一種緊湊的整數刻度,與大多數選色器使用的「角度加百分比」慣例不同。瀏覽器中的 RGB 轉 HSV 轉換器則採用 Android Color 參考(色相 0–360、飽和度 0–1、明度 0–1),並針對典型的 0–255 sRGB 輸入,以 R grDevices rgb2hsv 慣例獨立驗證。這種不一致正是許多初學者嘗試將設計工具的 HSV 值直接餵給 OpenCV 時,會看到「奇怪」輸出的實際原因:數學計算本身沒錯,但目標範圍被壓縮了。對於單一像素或測試顏色,計算機可在三個步驟內給出可辯護的 HSV 三元組,接著你再將結果縮放至 OpenCV 的範圍。對於完整影像陣列,你仍應使用 cv2.cvtColor,但可以先在這裡預先計算單一樣本,以在對整幀執行該函式前驗證轉換是否符合預期。

how to convert rgb image to hsv in opencv
how to convert rgb image to hsv in opencv

為什麼 OpenCV 的 HSV 範圍與標準不同

OpenCV 以 8 位元無號整數儲存 HSV,以保持影像陣列的緊湊。因此其色相軸的上限是 179 而非常見的 359,因為原始的 0–360 度範圍被除以二,且上界為互斥(不含端點)。飽和度與明度則縮放為 0–255,而非 0–1。這是一種封裝上的選擇,而非不同的色彩模型:其底層的 RGB→HSV 數學,與 Android、CSS 及各種圖形函式庫所用的分段公式相同。瀏覽器版的 RGB 轉 HSV 轉換器套用相同的公式,先顯示正統的結果,接著你再將輸出對應到 OpenCV 較小的整數範圍,然後指派給 NumPy 陣列。

如果你在網路上閱讀 HSV 教學,會看到三種常見範圍:

  • 設計工具與 CSS:色相 0–360 度,飽和度與明度 0–100%。
  • Android Color 與本計算機:色相 0–360 度,飽和度與明度 0–1。
  • OpenCV:色相 0–179,飽和度與明度 0–255。

前兩者之間的轉換只是單位變更(乘以或除以 100)。轉換到 OpenCV 則是一個封裝步驟:將色相除以 2,並將飽和度、明度乘以 255。知道目標端期望哪個範圍,是工作管線能否正常運作,以及它會不會悄悄地把紅色對應成垃圾結果的差別所在。

色相角度在色環上的位置

色相是大多數程式設計師最先接觸到的 HSV 元件,而六個主要與次要位置在所有實作中都是穩定的。Android Color 參考將同樣六個錨點視為正統的旋轉基準,下方的計算機也以同樣的 0–360 圓回報數值。當你看到一個色相角度並想知道它代表什麼顏色,或想驗證轉換後的結果是否指向你預期的方向時,可用此表格作為快速的視覺對照表。

色相(度)顏色
0紅色
60黃色
120綠色
180青色
240藍色
300洋紅

在 OpenCV 的壓縮範圍中,同樣六個錨點要除以二:0、30、60、90、120 與 150。若轉換後的 OpenCV 值為 60,以標準術語來說即為色相 120 度:綠色。若轉換值為 90,以標準術語來說即為色相 180 度:青色。在解讀管線輸出時,請將此表隨時備用。

使用瀏覽器工具轉換單一 RGB 樣本

若要快速處理測試顏色、取樣的像素,或想在呼叫 OpenCV 前驗證某個調色盤值,瀏覽器版的 RGB 轉 HSV 轉換器是最快的途徑。該工具接受三個整數通道,執行標準的最大通道分段數學,並回傳以度數表示的色相、以百分比表示的飽和度與明度,同時附上原始 HEX 與一個會在你調整任一通道時即時更新的色塊。

  1. 輸入介於 0 到 255 之間的整數紅、綠、藍通道值。
  2. 選擇轉換為 HSV,讀取以度數表示的色相,以及以百分比表示的飽和度與明度。
  3. 在複製數值之前,先確認目標端期望的是「度數加百分比」、「零到一的小數」,還是「緊湊的整數範圍」。

僅接受介於 0 到 255 之間的有限整數通道。小數輸入、空欄位、負數,以及大於 255 的值會明確產生錯誤,而不是被默默地四捨五入。這種嚴格的邊界可避免一個打字錯誤變成「看似合理但其實不同」的顏色,當來源是從選色器取得的 8 位元 RGB 代碼時尤其有用。Alpha 不在討論範圍內,因為透明度並不會改變底層三個通道的 RGB 至 HSV 計算。

如果你需要反向轉換 — 例如,手上有一組來自腳本的 HSV 三元組,並想將它對比回 RGB — 可參閱關於在 Roblox Studio 中將 HSV 轉換為 RGB的相關指南,該文使用了同樣的色相錨點位置表。

在 OpenCV 中將 RGB 轉換為 HSV:縮放至函式庫範圍

一旦從瀏覽器工具取得結果,下一步就是將其壓縮至 OpenCV 的整數範圍。此對映對工具所產生的任何色相都是無損的,因為將度數除以二必定落在 OpenCV 的 0–179 範圍內。其數學公式與 R grDevices rgb2hsv 參考完全相同,因此你只不過是在重新縮放輸出。

  1. 使用上述三個步驟,在瀏覽器工具中計算 RGB 至 HSV 值,並記下以度數表示的色相、以百分比表示的飽和度,以及以百分比表示的明度。
  2. 使用 H_opencv = H_degrees / 2 將色相轉換至 OpenCV 範圍。例如,色相 120 度會變為 60。
  3. 使用 S_opencv = S_percent × 255 / 100 將飽和度轉換至 OpenCV 範圍。指派前四捨五入至最接近的整數。
  4. 使用 V_opencv = V_percent × 255 / 100 將明度轉換至 OpenCV 範圍。指派前四捨五入至最接近的整數。
  5. 如果你處理的是單一像素,請將這三個值指派給 dtype 為 uint8 的 NumPy 陣列;若要填入遮罩,則指派給一個 3 通道的影像陣列。

如果你處理的是整張影像而非單一像素樣本,可跳過瀏覽器步驟,直接呼叫 cv2.cvtColor(img, cv2.COLOR_BGR2HSV)。OpenCV 預設期望 BGR 排序,因此在呼叫前請先交換紅與藍通道:bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR),然後再進行轉換。OpenCV 官方文件與 android.graphics.Color 參考所描述的底層公式相同,因此無論輸入是由哪個工具產生,結果都是一致的。

實作範例:RGB (255, 128, 0)

為了說明從樣本顏色到 OpenCV 可用 HSV 三元組的完整路徑,讓我們考慮 sRGB 顏色 (255, 128, 0),它是一種飽和的橘色。

首先,將通道除以 255 以標準化:

  • R = 255 / 255 = 1.0000
  • G = 128 / 255 ≈ 0.5020
  • B = 0 / 255 = 0.0000

接著,找出最大值與最小值:

  • max = 1.0000 (R)
  • min = 0.0000 (B)
  • delta = max − min = 1.0000

明度即為最大值,因此 V = 1.0000,工具會將其顯示為 100.00%。飽和度為 delta 除以 max,因此 S = 1.0000 / 1.0000 = 1.0000,工具會將其顯示為 100.00%。色相使用紅色條款,因為 R 是最大通道:

H = 60 × ((G − B) / delta) = 60 × ((0.5020 − 0) / 1.0000) = 60 × 0.5020 = 30.12 度

現在將結果對映至 OpenCV 的整數:

  • H_opencv = 30.12 / 2 ≈ 15
  • S_opencv = 100 × 255 / 100 = 255
  • V_opencv = 100 × 255 / 100 = 255

該像素最終的 OpenCV 陣列在 H、S、V 順序下為 [15, 255, 255]。如果你將度數與百分比直接複製到 OpenCV,色相 30 將會是深紅色,而飽和度 100 則會完全超出上限刻度 — 這正是忘記處理刻度不一致時的典型症狀。

在瀏覽器工具與 cv2.cvtColor 之間做選擇

瀏覽器工具與 OpenCV 函式不可互換。它們服務於同一工作流程的不同階段,且在便利性與效能之間各有所取。當你只有單一顏色需要轉換、需要在寫程式前驗證理論、正在教學 RGB 至 HSV 的步驟,或想要一個乾淨的參考值以貼到單元測試時,請使用 RGB 轉 HSV 轉換器。計算在本機瀏覽器中執行,輸入值保持可見以便快速調整,且實作已透過黃金案例(包含六個主要與次要色環位置、黑色,以及中間灰)獨立對照 R grDevices rgb2hsv 慣例驗證過。

每當你要處理整張影像、套用閾值遮罩、以顏色切割物體,或在即時迴圈中執行任何運算時,請使用 cv2.cvtColor(img, cv2.COLOR_BGR2HSV)。該函式已向量化,可在單次呼叫中處理一幀內的每個像素,這也是處理影像大小陣列的唯一務實選擇。請將瀏覽器工具視為用來確認樣本的一種方式,而非函式庫呼叫的替代品。

請記住兩個與目標相關的注意事項。該工具不會讀取嵌入的影像描述檔,也不會在寬色域色彩空間之間轉換,因此如果你的來源是帶有描述檔標記的影像,請先取出 sRGB 三元組,再將其餵給計算機。此外,當三個通道全部相等時,實作會回報慣例上的佔位色相 0 度,因為差值與飽和度皆為零,色相在這種無彩度情況下沒有視覺意義。若你看到灰色樣本回傳色相 0,那是文件化的慣例,而非轉換中的錯誤。

若你在權衡各種選項,CMYK 轉 RGB 初學者指南:平易近人的英文逐步說明對此有詳細介紹。