8

私は2つの非常によく似た画像(具体的には2つのスクリーンショット)を持っており、画像のどの領域が変更されたかを見つけるための最良の(最も速い)方法を見つけようとしています(異なる領域を表す長方形の配列として)

いくつかの基準:

  • ピクセル精度である必要はありませんが、どんなに小さな変更でもすべて含める必要があります(つまり、単一ピクセルの変更で大きな誤差が許容される場合)
  • 高速である必要があります(理想的には、2x 1920x1080イメージは、今日購入した一般的な消費者向けマシンで20ms未満かかるはずです)
  • 構成可能なしきい値は必要ありません(ただし、これを可能にするソリューションがある場合は、すばらしいボーナスになります)
  • 入力画像は常に完全な無損失画像であると想定できます。

私には2つの実用的な解決策がありますが、1つはピクセルごとのブルートフォース計算であり、もちろん非常に低速です。もう1つは、2つの画像をさまざまなサイズのチャンクに分割し、各チャンクのチェックサムを計算しようとしましたが、これも非常に低速です。

私が何を構築しているのか疑問に思っている人のために-プラグインなしでブラウザで使用できる一種の(そしてより遅い)リモートデスクトップです。

4

2 に答える 2

3

ピクセルごとの比較を行う必要があります。そんなに遅くなくてもいいと思います。たとえば、コード:

        int size = 1920 * 1080 * 3;
        byte[] image1 = new byte[size];
        byte[] image2 = new byte[size];
        byte[] diff = new byte[size];

        var sw = new System.Diagnostics.Stopwatch();
        sw.Start();
        for (int i = 0; i < size; i++)
        {
            diff[i] = (byte) (image1[i] - image1[i]);
        }
        sw.Stop();       
        Console.WriteLine(sw.ElapsedMilliseconds);

私のラップトップでは約40ミリ秒で実行されます。グレースケールのみの場合、20 ミリ秒未満で実行されます。実際の画像データを使用する場合、diff[i] != 0は 2 つの画像の変化を示します。

Bitmap.GetPixelまたは別の遅いメソッドを使用してピクセル値を読み取っている場合、ソリューションが遅くなる可能性があります。その場合は、Bitmap.LockBitsを調べるか、安全でない方法を使用することをお勧めします。

于 2012-08-13T10:23:46.717 に答える
3

私の以前の回答は、その形式のために削除されました。より良い方法でもう一度書きます。

GPU を使用して 2 つの画像の画像の違いを計算することを検討しているかどうかを尋ねていました。GPU は CPU 計算と比較して高度に並列であるため、このソリューションは計算時間を大幅に向上させる可能性があります。

C# を使用すると、この目的で XNA を使用することができます。実際に、シングル パス HLSL (direct3D で GPU をプログラムするために使用されるもの) ピクセル シェーダーを使用して少しテストを行いました。

texture texture1;
texture texture2;

sampler textureSampler1 = sampler_state{
    Texture = <texture1>;
};

sampler textureSampler2 = sampler_state{
    Texture = <texture2>;
};

float4 pixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0{
    float4 color1 = tex2D(textureSampler1,TextureCoordinate);
    float4 color2 = tex2D(textureSampler2,TextureCoordinate);
    if((color1.r == color2.r) && (color1.g == color2.g) && (color1.b == color2.b)){
        color1.r = 0;
        color1.g = 0;
        color1.b = 0;
    }
    else{
        color1.r = 255;
        color1.g = 255;
        color1.b = 255;
    }

    return color1;
}


technique Compare
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 pixelShaderFunction();
    }
}

XNA 部分の計算は非常に単純です。Visual Studio で XNA のベース スニペットを使用して、描画関数を次のように記述しました。

protected override void Draw(GameTime gameTime) {
   Stopwatch sw = new Stopwatch();
   sw.Start();
   GraphicsDevice.Clear(Color.CornflowerBlue);
   e.Parameters["texture1"].SetValue(im1);
   e.Parameters["texture2"].SetValue(im2);
   spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, e);
   spriteBatch.Draw(im1,new Vector2(0,0),Color.White);
   spriteBatch.End();
   base.Draw(gameTime);
   sw.Stop();
   Console.WriteLine(sw.ElapsedMilliseconds);
}

im1 と im2 は、Texture2D としてロードされた 2 つの 1920*1080 色の bmp イメージであり、e はエフェクトとしてロードされた file.fx です。

この手法を使用すると、かなり通常のコンピューター (I5-2410m @ 2.3Ghz、4Gb RAM、Nvidia Geforce GT525m を搭載したラップトップ) で 17/18ms の計算時間が得られます。

これはプログラムの出力で、違いの画像が表示されています(1920 * 1080の画面がないため、これは非常にズームされています:>)、さらに2つの画像im1とim2がありますが、それらの間にはいくつかの小さな違いがあります: http ://img526.imageshack.us/img526/2345/computationtime.jpg

私は GPU プログラミングにかなり慣れていないので、時間の計算方法などについて大きな間違いを犯した場合は、遠慮なく教えてください。

編集:最初に注意すべきことは、「GPUは分岐をうまく処理できないため、重要な操作になる」ということを読んだところです。

よろしくお願いします

于 2012-08-13T19:35:38.437 に答える