2

次のようなRGB画像があります。

Img[3*(row*imgWidth+column)+0], //R
Img[3*(row*imgWidth+column)+1], //G
Img[3*(row*imgWidth+column)+2]  //B

各 RGB の各ピクセルの強度値を表します。画像の周りに 0 の境界線 (0 ~ 255 スケール) を埋め込むきれいな方法は何ですか? 境界線は任意の幅に調整できます。

私が思いつくことができる唯一のことは、行と列をほとんど手動で挿入することであり、非常に退屈な長いコードになります。

申し訳ありませんが、ライブラリは私がここで探しているものではありません

4

6 に答える 6

3

プラットフォームについては言及していませんが、x86 を使用している場合、Intel の Integrated Performance Primitives (IPP)ライブラリ、特にその画像処理ライブラリは、選択した色の画像の周囲に境界線を追加します。または、コピー、サイズ変更、またはその他のいくつかの操作の一部として。そして、それは非常に効率的なコードです。

于 2012-09-05T00:49:03.577 に答える
2

これは私が考えることができる最も読みやすい方法であり、これもかなり効率的です。、、、およびの寸法と必要なマージンのイメージがあるWidthHeightします。ゼロで埋められたbyのバッファを割り当てます。C++ では、便利なコンストラクターの 1 つを使用できます。LeftRightTopBottomWidth + Left + RightHeight + Top + Bottomstd::vector

const auto Channels = 3;

const auto TargetWidth = Width + Left + Right;
const auto TargetHeight = Height + Top + Bottom;

std::vector<uint8_t> target(TargetWidth * TargetHeight * Channels);

C 関数calloc()もオプションです。次に、ソース イメージの各行をターゲット イメージに、垂直方向のオフセットTopと水平方向のオフセットからコピーしますLeft。行をコピーするために使用std::copy()し、外側のループを行優先順で実行して、キャッシュ ミスを回避します。

for (int y = 0; y < Height; ++y) {
    const auto* const source_row = &source[y * Width * Channels];
    auto* const target_row = &target[(y + Top) * TargetWidth * Channels + Left];
    std::copy(source_row, source_row + Width * Channels, target_row);
}

std::copy()24 ビット RGB の代わりに 32 ビット RGB0またはRGBA を使用できる場合memcpy()は、適切に最適化された、より一貫した配置のおかげでコピーが高速になることがあります。OpenMPを使用できる場合は、ループの並列化を試すこともできます。

#pragma omp parallel for
for (int y = 0; y < Height; ++y) {
    // ...
}
于 2012-09-05T01:26:53.470 に答える
2

画像処理ライブラリ (Intel Performance Primitives、ImageMagick、Windows など) を既に使用している場合は、既にこれを行っている既存の関数を探してください。作成者が苦労して MMX または SSE 命令を使用した場合、ライブラリの実装はより高速になる可能性があります。

それができない場合は、Ed S. のソリューションと同様のソリューションを使用して独自のロールを作成できます。これがスケッチです。memset 呼び出しの数を半分に削減するなど、追加のマイクロ最適化が可能です。

unsigned char* padWithBlack(const unsigned char* in,
                            int inWidth, int inHeight,
                            int thickness)
{
    unsigned char* out = malloc((inWidth + thickness * 2) *
                                (inHeight + thickness * 2) * 3);

    // top border
    int topOrBottomOutBytes = (inWidth + thickness * 2) * thickness * 3;
    memset(out, 0, topOrBottomOutBytes);

    // middle section
    unsigned char* inRow  = in;
    unsigned char* outRow = out + topOrBottomOutBytes;
    for (int inY = 0; inY < inHeight; inY++) {
        // left border
        memset(outRow, 0, thickness * 3);
        outRow += thickness * 3;
        // center section
        memcpy(outRow, inRow, inWidth * 3);
        outRow += inWidth * 3;
        inRow  += inWidth * 3;
        // right border
        memset(outRow, 0, thickness * 3);
        outRow += thickness * 3;
    }

    // bottom border
    memset(out, 0, topOrBottomOutBytes);
}
于 2012-09-05T02:01:32.983 に答える
0

ビルド済みの画像処理ライブラリを見たことがありますか? 私は過去にImageMagickを使用しました。インストールが最も簡単ではありませんが、機能するようになると多くのことができます。あなたが望むものを正確に含みます。

また、プログラムで画像操作を実行する必要がある場合は、オープン ソースです。「400,000 行以上の C コード」と言っていますが、回避できる場合は触れないようにすることをお勧めします。

それが役立つことを願っています!

于 2012-09-05T00:37:20.797 に答える
0

考慮事項の 1 つは、境界線が元の画像を上書きしない限り、結果の画像はソースよりも大きくなければならないということです。後者の場合は問題のピクセルを上書きするだけですが、「より大きな出力」の場合は最初に新しい画像用のスペースを割り当てる必要があります。新しいヘッダーを割り当てたら (おそらく適切なヘッダーを生成するライブラリを介して)、古いヘッダーを行ごとに memcopy する必要があります (ギャップを考慮して)、bitblt のような長方形のスウォッチをコピーする高速 API を使用します。 、または本質的に同じことを行うライブラリを使用します。この方法は、画像形式自体によって異なります。単純bits[width*height-1] = {0};ビットマップのような形式は、行ごとの memcpy またはビット blt で動作しますが、png のような圧縮形式は、データ構造を解釈できるライブラリが必要になる場合があります。環境に既にライブラリ (MSVS や Qt など) がある場合は、それをそのまま使用することもできます。ただし、それができない場合は、他のポスターで推奨されているようなサードパーティのライブラリを使用できます。

于 2012-09-05T01:47:32.787 に答える
-1

だから...私は、ライブラリをとても単純なことに使うことを提案するつもりはありません。将来、より高度な操作を実行する必要がある場合は、必ず検討してください。とんでもない。

これは私が横たわっているいくつかのコードです。指定された場所に黒い四角形を描画します。必要に応じて、エッジの色だけに簡単に変更できます。24 bpp イメージを想定していることに注意してください。

void WriteDebugImage( const unsigned char* inImageBuf, int inImageWidth, int inImageHeight, int left, int top, int right, int bottom, unsigned char* outImage )
{   
    // copy the old image into the new one
    memcpy( outImage, inImageBuf, inImageWidth * inImageHeight * 3 );
    for( int x = left; x <= right; ++x )
    {
        outImage[3 * top * inImageWidth + 3 * x]     = 0;    //Top Edge
        outImage[3 * top * inImageWidth + 3 * x + 1] = 0;    //Top Edge
        outImage[3 * top * inImageWidth + 3 * x + 2] = 0;    //Top Edge

        outImage[3 * bottom * inImageWidth + 3 * x]     = 0; //Bottom Edge
        outImage[3 * bottom * inImageWidth + 3 * x + 1] = 0; //Bottom Edge
        outImage[3 * bottom * inImageWidth + 3 * x + 2] = 0; //Bottom Edge
    }

    for (int y = top; y <= bottom; ++y)
    {
        outImage[3 * y * inImageWidth + 3 * left]     = 0;  //Left Edge
        outImage[3 * y * inImageWidth + 3 * left + 1] = 0;  //Left Edge
        outImage[3 * y * inImageWidth + 3 * left + 2] = 0;  //Left Edge

        outImage[3 * y * inImageWidth + 3 * right]     = 0;  //Right Edge
        outImage[3 * y * inImageWidth + 3 * right + 1] = 0;  //Right Edge
        outImage[3 * y * inImageWidth + 3 * right + 2] = 0;  //Right Edge
    }
}
于 2012-09-05T00:39:01.920 に答える