1

32Bit RGB IMAGE をカスタム解像度に縮小するために使用するアルゴリズムは? アルゴリズムはピクセルを平均化する必要があります。

たとえば、100x100 の画像があり、サイズが 20x50 の新しい画像が必要な場合。最初のソース行の最初の 5 ピクセルの平均は、dest の最初のピクセルを示し、最初のソース列の最初の 2 つのピクセルの平均は、最初の dest 列のピクセルを示します。

現在私が行っているのは、最初に X 解像度で縮小し、その後 Y 解像度で縮小することです。このメソッドには 1 つの一時バッファーが必要です。

あなたが知っている最適化された方法はありますか?

4

7 に答える 7

6

あなたが探している用語は「リサンプリング」です。あなたの場合、画像のリサンプリングが必要です。あなたはすでに線形補間を行っているようですが、これは最速のはずです。ここに〜6つの基本アルゴリズムがあります。このテーマを深く掘り下げたい場合は、「リサンプリング カーネル」を調べてください。

于 2009-11-13T15:01:30.107 に答える
3

標準のC最適化(ポインター演算、固定小数点演算など)を実行した後、さらに賢い最適化を行う必要があります。(非常に)ずっと前に、X方向を最初にスケーリングするスケーラーの実装を見ました。水平方向に拡大縮小された画像を書き出す過程で、メモリ内で画像を90度回転させました。これは、Y方向のスケールの読み取りを行うときに、メモリ内のデータのキャッシュがより適切に調整されるようにするためでした。

この手法は、実行するプロセッサに大きく依存します。

于 2009-11-14T18:23:18.080 に答える
2

質問の最も重要な側面である「品質をどれだけ重視しているか」について言及するのを忘れています。ソース ピクセルの値をどのように組み合わせてデスティネーション ピクセルを作成するかを正確に気にしない場合、(少なくともほとんどの場合) 最速のピクセルが最悪の品質を生成します。

「非常に優れた品質を実現する最速のアルゴリズム」で応答したい場合は、画像のサンプリング/サイズ変更だけを扱うアルゴリズム分野全体を本質的にカバーしています。

そして、あなたはすでにアルゴリズムの最初のアイデアを概説しています:

最初のソース行の最初の 5 ピクセルの平均は、dest の最初のピクセルになります。

ソース ピクセルの各チャネルの平均値を計算するのは些細なことのように見えるかもしれません。それを行うサンプル コードを探していますか?

それとも、アルゴリズムの最初のドラフトに挑戦してくれる人を探していますか?

于 2009-11-13T13:42:59.750 に答える
2

これにより、適切なピクセルが平均化されます。

 w_ratio = src.w / dest.w
 h_ratio = src.h / dest.h

 dest[x,y] = 
    AVG( src[x * w_ratio + xi, y * h_ratio + yi] ) 
      where
           xi in range (0, w_ratio - 1), inc by 1
           yi in range (0, h_ratio - 1), inc by 1

境界条件については、別のループを実行します (ループ内に if はありません)。

C ライクなコードは次のとおりです。

src と dest はビットマップです:
* ピクセルのプロパティ src[x,y]
* 幅の
プロパティ src.w * 高さのプロパティ src.h

ピクセルは次のように定義されています。

追加

p1 = p1 + p2     
is same as
p1.r = p1.r + p2.r
p1.g = p1.g + p2.g
...

分割

p1 = p1 / c
p1.r = p1.r / c
p1.g = p1.g / c

定数 0 での評価

p1 = 0
p1.r = 0
p1.g = 0
...

簡単にするために、ピクセルコンポーネントの整数がオーバーフローした場合の問題は考慮しません...

float w_ratio = src.w / dest.w;
float h_ratio = src.h / dest.h;
int w_ratio_i = floor(w_ratio);
int h_ratio_i = floor(h_ratio);

wxh = w_ratio*h_ratio;

for (y = 0; y < dest.w; y++)
for (x = 0; x < dest.h; x++){
    pixel temp = 0;     

    int srcx, srcy;
    // we have to use here the floating point value w_ratio, h_ratio
    // otherwise towards the end it can get a little wrong
    // this multiplication can be optimized similarly to Bresenham's line
    srcx = floor(x * w_ratio);
    srcy = floor(y * h_ratio);

    // here we use floored value otherwise it might overflow src bitmap
    for(yi = 0; yi < h_ratio_i; yi++)
    for(xi = 0; xi < w_ratio_i; xi++)
            temp += src[srcx + xi, srcy + yi];
    dest[x,y] = temp / wxh;
}

Bresenham の回線最適化

于 2009-11-13T14:47:26.033 に答える
1

これは、速度と品質のトレードオフです。

まず第一に、あなたは正しいです。一方の次元を実行してから、もう一方の次元を実行すると、必要以上に遅くなります。あまりにも多くのメモリの読み取りと書き込み。

あなたの大きな選択は、分数ピクセルをサポートするかどうかです。あなたの例は100x100から20x50です。したがって、10ピクセルは1にマップされます。100x100から21x49に変更する場合はどうなりますか?ソースピクセルの境界で操作しますか、それとも小数ピクセルを取り込みますか?100x100から99x99の場合はどうしますか?

何が最速かを言う前に、何を受け入れても構わないと思っているかを教えてください。

また、収縮の極端な可能性についても教えてください。ソースと宛先の違いは何桁になるでしょうか。ある時点で、ソース内の代表的なピクセルのサンプリングは、すべてのピクセルを平均化するよりも悪くはありません。ただし、代表的なピクセルの選択には注意が必要です。そうしないと、多くの一般的なパターンでエイリアシングが発生します。

于 2009-11-14T18:24:09.747 に答える
1

冗長な説明を探している場合は、この記事が役立つことがわかりました。一方、数式をより多く扱う場合は、ここで説明されている高速な画像ダウンスケーリングの方法があります。

于 2009-11-13T13:30:11.763 に答える
0

あなたがしているのは最適化された方法です。唯一速いものは最近傍と呼ばれ、範囲の中央のピクセルを平均化しようとせずに取得するだけです。元の画像に細部がある場合、品質は大幅に低下しますが、元の画像が単純な場合は許容できる場合があります。

于 2009-11-13T13:50:24.747 に答える