4

System.Drawing.Graphicsクラスを使用して画像のサイズを変更すると、結果の画像の右と下の境界から1ピクセルが失われることがわかりました。これは私のコードまたは.Netの問題のどこかにあるバグですか?テストコード:

public static void Resize(string imagePath,int width) {
  InterpolationMode[] interpolationModes = new InterpolationMode[]{InterpolationMode.Bicubic, InterpolationMode.Bilinear, InterpolationMode.Default, InterpolationMode.High,
    InterpolationMode.HighQualityBicubic, InterpolationMode.HighQualityBilinear, InterpolationMode.Low, InterpolationMode.NearestNeighbor};
  SmoothingMode[] smoothingModes = new SmoothingMode[]{SmoothingMode.AntiAlias, SmoothingMode.Default, SmoothingMode.HighQuality, SmoothingMode.HighSpeed,
    SmoothingMode.None};

  for(int i = 0; i < interpolationModes.Length; i++) {
    for(int j = 0; j < smoothingModes.Length; j++) {
      Resize(imagePath, width, interpolationModes[i], smoothingModes[j]);
    }
  }
}


public static void Resize(string imagePath,int width, InterpolationMode interpolationMode, SmoothingMode smoothingMode) {
  Image imgPhoto = Image.FromFile(imagePath);
  float percent = (float)width / (float)imgPhoto.Width;
  int height = (int)(imgPhoto.Height * percent);

  Bitmap bmPhoto = new Bitmap(width, height, PixelFormat.Format24bppRgb);
  bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

  Graphics grPhoto = Graphics.FromImage(bmPhoto);
  grPhoto.InterpolationMode = interpolationMode;
  grPhoto.SmoothingMode = smoothingMode;

  grPhoto.DrawImage(imgPhoto,
  new Rectangle(0, 0, width, height),
  new Rectangle(0, 0, imgPhoto.Width, imgPhoto.Height ),
  GraphicsUnit.Pixel);

  grPhoto.Dispose();

  string fileName = Path.GetFileName(imagePath);
  string path = Path.GetDirectoryName(imagePath)+"\\resized";

  if (!Directory.Exists(path))
    Directory.CreateDirectory(path);

  bmPhoto.Save(String.Format("{0}\\{1}_{2}_{3}", path, interpolationMode.ToString(), smoothingMode.ToString(),fileName));
}

ソース画像: ソース画像http://img110.imageshack.us/img110/4876/sampleaa2.jpg

結果: 結果http://img110.imageshack.us/img110/2050/resizedsamplesy4.png

PS私はInterpolationModeとSmoothingModeの既存のすべての組み合わせを試しました。それらのどれも許容できる結果を与えませんでした。

4

5 に答える 5

2

これは.NETグラフィックスのバグであり、非常に厄介なものです。丸め誤差やアルゴリズムの問​​題ではありません。100x100のビットマップを作成し、パラメーターの1つとして100x100の長方形を使用してDrawRectangleを呼び出すと、同じ問題の変形が見られます。描画された長方形の下側または右側は表示されません。

于 2009-01-21T19:58:30.527 に答える
2

この質問から恥知らずに答えを持ち上げると、これで修正されることがわかりました。

using (ImageAttributes wrapMode = new ImageAttributes())
{
    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
    g.DrawImage(input, rect, 0, 0, input.Width, input.Height, GraphicsUnit.Pixel, wrapMode);
}
于 2011-11-29T14:35:52.037 に答える
1

これは、元の線の幅が1ピクセルしかない場合に発生します。サイズを変更すると、アルゴリズムによって左右の境界線が「トリミング」されたように見えます。実際に発生しているのは、アルゴリズムがピクセルの色相/色/彩度/配置に基づいてある程度の重要性を置いている場合です。内部セルが優先され、境界が失われると見なされます。AdobePhotoshopやCorelPaintShopProなどのさまざまなグラフィックアプリケーションには、このようなことを回避するためのさまざまなサイズ変更オプション[補間モード]が用意されています。補間モードを別のものに変更する必要があります。しばらくGDI+を使っていないので、利用できるモードを忘れてしまいました。それぞれのモードを試して、どれが最も受け入れられるかを確認してください。

私がおそらくすることは、国境の完全性を保証するためにこれです:

  • 元の画像から境界線を取り除きます
  • 画像の残りの部分のサイズを変更します
  • 結果の画像に境界線を追加します

このようにして、境界線は変更されません。サイズ変更された画像を囲む1つの赤いピクセルです。

于 2009-01-21T19:47:40.453 に答える
0

スケーリングしているパーセンテージが常に整数の結果をもたらすとは限らないことを考えると、それは境界を生成する丸め誤差につながるでしょう。

いずれかの次元の丸めによってピクセル境界が追加されるかどうかを判断する必要があります(丸めを確認できます)。含まれている場合は、新しいビットマップを作成してから、境界線を含まない画像のセクションをコピーできます。

于 2009-01-21T19:46:54.870 に答える
0

私は、オープンソースの画像サイズ変更ライブラリで、この問題に長い間苦労してきました。

私が見つけた最善の解決策は、HighQualityBicubic、WrapMode.TileFlipXY を使用し、DrawImage の平行四辺形オーバーロードを使用することでした。結果はまだ外側のピクセルのわずかな劣化を示していますが、何もトリミングされていません。グラフィックス オブジェクトの背景色を外縁の色に近い色に設定することで、その問題を最小限に抑えることもできます。

ソースの抜粋:

g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.CompositingMode = CompositingMode.SourceOver;


s.copyAttibutes.SetWrapMode(WrapMode.TileFlipXY);

s.destGraphics.DrawImage(s.sourceBitmap, PolygonMath.getParallelogram(s.layout["image"]), s.copyRect, GraphicsUnit.Pixel, s.copyAttibutes);

これで問題が解決しない場合は、SetResolution 呼び出しを無効にすることをお勧めします。これが最後に残っている変数だからです。

于 2011-05-18T18:11:10.750 に答える