13

.NET での画像のスケーリングに問題があります。次の例のように、標準の Graphics 型を使用して画像のサイズを変更します。

public static Image Scale(Image sourceImage, int destWidth, int destHeight)
{
        Bitmap toReturn = new Bitmap(sourceImage, destWidth, destHeight);

        toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);

        using (Graphics graphics = Graphics.FromImage(toReturn))
        {
            graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.DrawImage(sourceImage, 0, 0, destWidth, destHeight);
        }
        return toReturn;
    }

しかし、サイズ変更された画像には大きな問題があります。グレーと黒の境界線があり、それらのない画像を作成することが非常に重要です。

それらが表示される理由と、それらを消すにはどうすればよいですか?

サンプル出力:

サンプル出力

4

9 に答える 9

7

これは、エッジ周辺のピクセルが正しく補間されていないことが原因である可能性があります。私はこれをバグと呼んでいます。

ただし、解決策は次のとおりです。

graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;

// Draw your image here.

graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

// Draw it again.

これが行うことは、最初にエッジが正しく塗りつぶされた「背景」を描画し、次に補間を使用して再度描画することです。補間が必要ない場合、これは必要ありません。

于 2013-02-15T12:07:08.763 に答える
7

試す:

graphic.CompositingMode = CompositingMode.SourceCopy;
于 2009-12-07T17:36:57.877 に答える
7

問題は、toReturnデフォルトでビットマップの背景が黒くなっていることにあります。その上に新しい画像をコピーすると、黒またはグレーの境界線ができます。

解決策は、次のように呼び出して、黒のデフォルトの背景を削除することです。

toReturn.MakeTransparent();

この行の後、背景色なしで新しい画像を描画するため、境界線が消えます。

于 2011-08-07T17:16:42.420 に答える
7

正解は、他のいくつかの回答からつなぎ合わせることができますが、どれも完全ではなく、いくつかの非常に悪いアイデア (画像を 2 回描画するなど) を提示するものもあります。

問題

アーティファクトが表示される理由は 3 つあります。

  1. デフォルトGraphics.PixelOffsetMode設定では、ピクセル値が正しくサンプリングされず、特にエッジ周辺で画像がわずかに歪んでしまいます。
  2. InterpolationMode.HighQualityBicubicデフォルトでは透明である画像の端を越えてピクセルをサンプリングします。これらの透明なピクセルは、サンプラーによってエッジ ピクセルと混合され、半透明のエッジになります。
  3. 透明度をサポートしない形式 (JPEG など) で半透明の画像を保存すると、透明度の値が黒に置き換えられます。

これらすべてを合計すると、セミブラック (グレー) のエッジになります。

投稿したコードには、他にもいくつかの問題があります。

使用したBitmapコンストラクターは、元の画像のサイズを変更して新しい画像を初期化しBitmapているため、サイズ変更操作を 2 回行っています。空白のキャンバスを作成するには、目的のサイズだけでコンストラクターのオーバーロードを使用する必要があります。

このBitmapクラスは、メモリ内のイメージの管理されていないコピーを表すことに注意してください。メモリを使い終わったときにメモリを解放するように GDI+ に指示できるように、メモリを破棄する必要があります。return を受け取るコードでそれを行っていると思いますが、Image他の誰かがこのコードを借りた場合に備えて指摘します。

コードで使用されている設定は、他のCompositingQuality.HighQuality設定が正しく行われていれば視覚的な効果はなく、実際にはデフォルト値のCompositingMode.SourceOver. CompositingQuality設定と設定を省略してCompositingMode.SourceCopy、より優れたパフォーマンスで同じ結果を得ることができます。

コードで使用されているSmoothingMode設定は にはまったく影響しないDrawImage()ため、削除できます。

解決

これらのアーティファクトを削除する正しい方法はPixelOffsetMode.HalfImageAttributesオブジェクトを使用してエッジ タイリングを指定し、HighQualityBicubicサンプラーがサンプリングする透明なピクセル以外のものを持つようにすることです。

Graphicsクラス設定と、それらが画質とパフォーマンスに与える影響について詳しくは、 http: //photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-をご覧ください。それが影響する

修正されたコードは次のようになります。

public static Image Scale(Image sourceImage, int destWidth, int destHeight)
{
    var toReturn = new Bitmap(destWidth, destHeight);

    using (var graphics = Graphics.FromImage(toReturn))
    using (var attributes = new ImageAttributes())
    {
        toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);

        attributes.SetWrapMode(WrapMode.TileFlipXY);

        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.PixelOffsetMode = PixelOffsetMode.Half;
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.DrawImage(sourceImage, Rectangle.FromLTRB(0, 0, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attributes);
    }

    return toReturn;
}
于 2017-01-18T11:49:27.557 に答える
3

写真の端からサンプリングしたためです。

于 2009-12-07T17:05:52.203 に答える
2

以下はどのように機能しますか? これは、私が同じことをするために使用したコードです。私が気付いた主な違いは、SetResolution を使用していないことです (私の場合は正方形の入力と出力を想定していました)。

/// <summary>
/// Resizes a square image
/// </summary>
/// <param name="OriginalImage">Image to resize</param>
/// <param name="Size">Width and height of new image</param>
/// <returns>A scaled version of the image</returns>
internal static Image ResizeImage( Image OriginalImage, int Size )
{
    Image finalImage = new Bitmap( Size, Size );

    Graphics graphic = Graphics.FromImage( finalImage );

    graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
    graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
    graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

    Rectangle rectangle = new Rectangle( 0, 0, Size, Size );

    graphic.DrawImage( OriginalImage, rectangle );

    return finalImage;
}
于 2009-12-07T17:03:27.440 に答える
1

これは、画像を描画するときのエッジのスムージング(背景とのブレンド)が原因です。

スムージングを有効にしない場合と有効にした場合の2回描画できます。または、少し大きく描くこともできます。または、元の背景色がわかっている場合は、最初に画像を背景色で塗りつぶすことができます。

于 2009-12-07T17:22:53.063 に答える
1

これらのどれも私にとってはうまくいきませんでした。

ただし、フォーマットを変更する

System.Drawing.Imaging.PixelFormat.Format24bppRgb

System.Drawing.Imaging.PixelFormat.Format32bppArgb 

問題を解決しましたか

using (System.Drawing.Bitmap newImage = new System.Drawing.Bitmap(newWidth, newHeight,
                // System.Drawing.Imaging.PixelFormat.Format24bppRgb // OMG bug
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb 
                ))
            {
于 2015-01-21T11:45:09.550 に答える