web-dev-qa-db-ja.com

「標準」RGBからグレースケールへの変換

私は、JPEG画像を取り、PGM(Portable Gray Map)バージョンを返すコンバーターアルゴリズムを作成しようとしています。問題は、古典的なRGB形式から始めて、最終的なピクセルに割り当てる値(つまり、0-> 255)に関して、「公式の」JPG-> PGMコンバーターがどのように機能するのか理解できないことです。

最初は次の式を使用しました(OpenCVのCV_RGB2GRAY変換で使用されるものと同じです)。

0.30 * R + 0.59 * G + 0.11 * B = val

結果をテストするための簡単なコードを作成しました。カラーイメージとそのPGMバージョン(既にGIMPを使用して変換されています)を取ります。次に、前の式を使用してカラーイメージを変換します。目標は、PGM入力と等しいピクセル単位のグレースケールイメージを作成することです。

この時点では、同じ値は返されません。手伝って頂けますか?

17
TheUnexpected

問題は、古典的なRGB形式から始めて、最終的なピクセルに割り当てる値(つまり、0-> 255)に関して、「公式の」JPG-> PGMコンバーターがどのように機能するのか理解できないことです。

これらの「公式」ツールが使用している変換には、おそらくガンマ調整があります。
つまり、これは単なる線形変換ではありません。

詳細については、このウィキペディアのセクションを参照してください: 色をグレースケールに変換します

Csrgbの数式を使用したいと思います。
実際に試して、期待した結果と一致するかどうかを確認してください。

基本的には、次のようにします。

  1. R, G, Bの色(それぞれ[0,1]の範囲)
    • 代わりに0..255の範囲にある場合は、単に255.0で除算します
  2. 計算Clinear = 0.2126 R + 0.7152 G + 0.0722 B
    • これはおそらく、以前に適用していた線形変換です
  3. Csrgb に基づいて、その式に従ってClinearを計算します
    • これは、欠落していたnonlinearガンマ補正ピースです
    • チェックアウト this WolframAlpha plot
    • Csrgb = 12.92 Clinearの場合Clinear <= 0.0031308
    • Csrgb = 1.055 Clinear1/2.4 - 0.055の場合Clinear > 0.0031308
24
Timothy Shields

「Y平面」に関するハロルドのポイント:標準カラーJPEGは YCbCr colorspaceを使用してエンコードされます。ここで、Yは輝度コンポーネント(つまり、明るさ)で、CbとCrは青の差と赤です。差クロマ成分。したがって、カラーJPEGをグレースケールに変換する1つの方法は、単にCbおよびCrコンポーネントを削除することです。

-grayscaleオプションを使用して、これを無損失で実行できるjpegtranというユーティリティがあります。 (ロスレス部分は、PGMではなくJPEGで終了したい場合にのみ重要です 生成ロス を回避します。)いずれにしても、これはおそらくこの変換を行う最も速い方法です。画像をピクセルにデコードすることさえないので、それぞれについて計算を行うことはほとんどありません。

4
Robert Fleming

OPENCV PYTHONでRGBイメージをグレースケールに変換する簡単なアルゴリズム!

コメントを使用したので、コードは自明ですが、すばやく機能します。

import cv2
import numpy as np
img1 = cv2.imread('opencvlogo.png')
row,col,ch = img1.shape
g = [ ]  #the list in which we will stuff single grayscale pixel value inplace of 3 RBG values
#this function converts each RGB pixel value into single Grayscale pixel value and appends that value to list 'g'
def rgb2gray(Img):
    global g
    row,col,CHANNEL = Img.shape
    for i in range(row) :
        for j in range(col):
        a =      (   Img[i,j,0]*0.07  +  Img[i,j,1]*0.72 +    Img[i,j,2] *0.21   ) #the algorithm i used id , G =  B*0.07 + G*0.72 + R* 0.21
                                                                                   #I found it online
        g.append(a)
rgb2gray(img1)  #convert the img1 into grayscale
gr = np.array(g)  #convert the list 'g' containing grayscale pixel values into numpy array
cv2.imwrite("test1.png" , gr.reshape(row,col)) #save the image file as test1.jpg

だから私はこの画像ファイルを使用しました... enter image description here

私のプログラムはグレースケールファイル..

enter image description here

1
bad programmer

理論的には、数ピクセル(この場合は3)で、それらのアルゴリズムの動作を決定できます。 3つのピクセル(p1、p2、p3)、それらのRGB値、およびPGMグレー値を選択すると、次のようになります。

RedConstant * p1.redValue + GreenConstant * p1.greenValue + BlueConstant * p1.blueValue = p1.grayValue

RedConstant * p2.redValue + GreenConstant * p2.greenValue + BlueConstant * p2.blueValue = p2.grayValue

RedConstant * p3.redValue + GreenConstant * p3.greenValue + BlueConstant * p3.blueValue = p3.grayValue。

次に、この問題を解決し(「方程式ソルバー」などを検索)、それらが使用する定数を確認します。

1
Fabinout

デフォルトのRGB ColorModelの単一の入力ピクセルを単一の灰色のピクセルに変換します。

/* Convertation function 
 * @param x    the horizontal pixel coordinate
 * @param y    the vertical pixel coordinate
 * @param rgb  the integer pixel representation in the default RGB color model
 * @return a gray pixel in the default RGB color model.*/

    public int filterRGB(int x, int y, int rgb) {
    // Find the average of red, green, and blue.
    float avg = (((rgb >> 16) & 0xff) / 255f +
                 ((rgb >>  8) & 0xff) / 255f +
                  (rgb        & 0xff) / 255f) / 3;
    // Pull out the alpha channel.
    float alpha = (((rgb >> 24) & 0xff) / 255f);

    // Calculate the average.
    // Formula: Math.min(1.0f, (1f - avg) / (100.0f / 35.0f) + avg);
    // The following formula uses less operations and hence is faster.
    avg = Math.min(1.0f, 0.35f + 0.65f * avg);
    // Convert back into RGB.
   return (int) (alpha * 255f) << 24 |
          (int) (avg   * 255f) << 16 |
          (int) (avg   * 255f) << 8  |
          (int) (avg   * 255f);
}
0
Tomka Koliada