26

HTML5キャンバスピクセル処理を通じて効果を適用する画像処理プログラムを書いています。しきい値処理、Vintaging、およびColorGradientピクセル操作を達成しましたが、信じられないほど画像のコントラストを変更できません。私は複数の解決策を試しましたが、画像の明るさが多すぎてコントラスト効果が低くなります。これらの効果をネイティブに実現しようとしているため、Javascriptライブラリを使用する予定はありません。

基本的なピクセル操作コード:

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 //Note: data[i], data[i+1], data[i+2] represent RGB respectively
data[i] = data[i];
data[i+1] = data[i+1];
data[i+2] = data[i+2];
}

ピクセル操作の例

値はRGBモードです。つまり、data[i]は赤色です。したがって、data [i] = data [i]*2の場合; そのピクセルの赤チャンネルの明るさは2倍に増加します。例:

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 //Note: data[i], data[i+1], data[i+2] represent RGB respectively
 //Increases brightness of RGB channel by 2
data[i] = data[i]*2;
data[i+1] = data[i+1]*2;
data[i+2] = data[i+2]*2;
}

*注:コードを完成させるようにお願いしているわけではありません!それはただの恩恵です!ピクセル操作のコントラストがどのように可能であるかを示すアルゴリズム(擬似コードでさえ)を求めています! 誰かがHTML5キャンバスの画像コントラストに優れたアルゴリズムを提供できれば幸いです。

4

7 に答える 7

26

Schahriar SaffarShargh による答えを試した後、コントラストが動作するはずのように動作しませんでした。私はついにこのアルゴリズムに出会いました、そしてそれは魅力のように機能します!

アルゴリズムの詳細については、この記事とそのコメント セクションをお読みください。

function contrastImage(imageData, contrast) {

    var data = imageData.data;
    var factor = (259 * (contrast + 255)) / (255 * (259 - contrast));

    for(var i=0;i<data.length;i+=4)
    {
        data[i] = factor * (data[i] - 128) + 128;
        data[i+1] = factor * (data[i+1] - 128) + 128;
        data[i+2] = factor * (data[i+2] - 128) + 128;
    }
    return imageData;
}

使用法:

var newImageData = contrastImage(imageData, 30);

うまくいけば、これは誰かにとって時間の節約になります。乾杯!

于 2013-08-28T18:02:42.940 に答える
4

この JavaScript の実装は、SVG/CSS3 の「コントラスト」の定義に準拠しています (次のコードは、キャンバス イメージをまったく同じようにレンダリングします)。

/*contrast filter function*/
//See definition at https://drafts.fxtf.org/filters/#contrastEquivalent
//pixels come from your getImageData() function call on your canvas image
contrast = function(pixels, value){
    var d = pixels.data;
    var intercept = 255*(-value/2 + 0.5);
    for(var i=0;i<d.length;i+=4){
        d[i] = d[i]*value + intercept;
        d[i+1] = d[i+1]*value + intercept;
        d[i+2] = d[i+2]*value + intercept;
        //implement clamping in a separate function if using in production
        if(d[i] > 255) d[i] = 255;
        if(d[i+1] > 255) d[i+1] = 255;
        if(d[i+2] > 255) d[i+2] = 255;
        if(d[i] < 0) d[i] = 0;
        if(d[i+1] < 0) d[i+1] = 0;
        if(d[i+2] < 0) d[i+2] = 0;
    }
    return pixels;
}
于 2015-12-10T13:30:27.117 に答える
3

闇と光を分離するか、技術的にはRGBスケールで127(R + G + B / 3の平均)未満のものは黒で、127を超えるものは白であるため、効果を使用する必要があることがわかりました。あなたのコントラストのレベルによって、黒から10のコントラストなどの値を引いて、同じ値を白に追加します!

次に例を示します。RGB カラー [105,40,200] の 2 つのピクセルがあります。[255,200,150] したがって、最初のピクセル 105 + 40 + 200 = 345、345/3 = 115、および 115 は 255 の半分である 127 より小さいことがわかっているので、ピクセルは [0,0,0] に近いと見なします。したがって、コントラストを 10 マイナスしたい場合は、平均で各色から 10 を引きます。したがって、各色の値を、この場合は 115 であった合計の平均で割って、コントラストで時間をかけ、最終値を差し引く必要があります。その特定の色:

たとえば、ピクセルから 105 (赤) を取得するので、RGB の合計の平均で割ります。これは 115 で、私のコントラスト値の 10 を掛けると (105/115)*10 となり、約 9 になります (四捨五入する必要があります)。次に、105 からその 9 を引いて、色が 96 になるようにします。暗いピクセルに 10 のコントラストを付けた後の赤。

したがって、ピクセルの値は [96,37,183] になります! (注:コントラストのスケールはあなた次第です!しかし、最終的には1から255のようなスケールに変換する必要があります)

明るいピクセルについても、コントラスト値を減算する代わりに追加することを除いて、同じことを行います! 255 または 0 の制限に達した場合は、その特定の色の加算と減算を停止します。したがって、明るいピクセルである私の2番目のピクセルは[255,210,157]になります

コントラストを追加すると、明るい色が明るくなり、暗い色が暗くなるため、写真にコントラストが追加されます!

サンプルの Javascript コードを次に示します (まだ試していません)。

var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
 var contrast = 10;
 var average = Math.round( ( data[i] + data[i+1] + data[i+2] ) / 3 );
  if (average > 127){
    data[i] += ( data[i]/average ) * contrast;
    data[i+1] += ( data[i+1]/average ) * contrast;
    data[i+2] += ( data[i+2]/average ) * contrast;
  }else{
    data[i] -= ( data[i]/average ) * contrast;
    data[i+1] -= ( data[i+1]/average ) * contrast;
    data[i+2] -= ( data[i+2]/average ) * contrast;
  }
}
于 2013-01-04T02:27:46.653 に答える
1

これを達成する方法については、OpenCV のドキュメントを参照してください:明るさとコントラストの調整

次に、デモ コードがあります。

 double alpha; // Simple contrast control: value [1.0-3.0]
 int beta;     // Simple brightness control: value [0-100]

 for( int y = 0; y < image.rows; y++ )
 { 
      for( int x = 0; x < image.cols; x++ )
      { 
          for( int c = 0; c < 3; c++ )
          {
              new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
          }
      }
 }

あなたはjavascriptに翻訳できると思います。

于 2012-05-09T18:38:14.273 に答える
1

ビンテージ化することで、LUTS を適用しようとしていると思います..最近、キャンバス ウィンドウに色処理を追加しようとしています。実際に「LUTS」をキャンバス ウィンドウに適用する場合は、imageData が返す配列を実際に LUT の RGB 配列にマップする必要があると思います。

(光の錯覚から) 例として、1D LUT の開始は次のようになります。

R, G, B 
3, 0, 0 
5, 2, 1 
7, 5, 3 
9, 9, 9

つまり、次のことを意味します。

For an input value of 0 for R, G, and B, the output is R=3, G=0, B=0 
For an input value of 1 for R, G, and B, the output is R=5, G=2, B=1 
For an input value of 2 for R, G, and B, the output is R=7, G=5, B=3 
For an input value of 3 for R, G, and B, the output is R=9, G=9, B=9

これは奇妙な LUT ですが、R、G、または B 入力の特定の値に対して、R、G、および B 出力の特定の値があることがわかります。

したがって、ピクセルの入力値が RGB で 3、1、0 の場合、出力ピクセルは 9、2、0 になります。

この間、imageData で遊んだ後、それが Uint8Array を返し、その配列の値が 10 進数であることにも気付きました。ほとんどの 3D LUT は Hex です。したがって、このすべてのマッピングの前に、まず配列全体である種の 16 進数から 10 進数への変換を行う必要があります。

于 2013-04-22T07:46:29.643 に答える