

C#でWritableBitmapをLanczos縮小するためにさまざまなwebページを参考に
下記コードを書いておりますが、
(文字数の関係で見づらく申し訳ありません)
添付画像のとおり、縮小するとキレイに縮小されず、格子状?のあるパターンで
模様が入ってしまいます。また、かすれたりしているように思われます。
ずっと考えているのですが、どこが悪いのか分かりません。
どなたかご教授ください。
private WriteableBitmap Lanzcos3Scaler(WriteableBitmap procBmp)
{
//処理対象データのデータを取得
int bpp = procBmp.Format.BitsPerPixel / 8;
int w = procBmp.PixelWidth;
int h = procBmp.PixelHeight;
int stride = w * bpp;
byte[] Source = new byte[w * bpp * h];
//byte配列にもとデータをコピー
procBmp.CopyPixels(Source, stride, 0);
//処理
int n = 3; // N値
int nx = n - 1;
//スケールを定義
double scale = 0.4;
//出力先を定義
int w2 = (int)(w * scale),
h2 = (int)(h * scale);
Int32Rect Rect = new Int32Rect(0, 0, w2, h2);
WriteableBitmap resBmp = new WriteableBitmap(w2, h2, procBmp.DpiX, procBmp.DpiY, procBmp.Format, null);
int bpp2 = resBmp.Format.BitsPerPixel / 8;
int stride2 = w2 * bpp2;
byte[] Result = new byte[w2 * bpp2 * h2];
//処理
Parallel.For(0, h2, y =>
{
for (int x = 0; x < w2; x++)
{
//ソース側の対応点計算
double x0 = (x + 0.5) / scale;
double y0 = (y + 0.5) / scale;
//ソース側の対応インデックス計算
int xBase = (int)x0;
int yBase = (int)y0;
//色要素を格納する配列を作成
byte[] colors = new byte[bpp];
for (int i = 0; i < bpp; i++) colors[i] = 0;
double[] color_element = new double[bpp];
for (int i = 0; i < color_element.Length; i++) color_element[i] = 0.0;
double w_total = 0.0;
// 周辺(a*2)^2画素を取得して処理
for (int i = -nx; i <= n; i++)
{
for (int j = -nx; j <= n; j++)
{
int xCurrent = xBase + i;
int yCurrent = yBase + j;
// 距離決定
double distX = ((double)xCurrent + 0.5) - x0;
double distY = ((double)yCurrent + 0.5) - y0;
double dist = Math.Sqrt(distX * distX + distY * distY);
// 重み付け
double weight = 0.0;
if (dist == 0.0)
{
weight = 1.0;
}
else if (dist < (double)n)
{
double dPI = Math.PI * dist; //MessageBox.Show(dist.ToString());
weight = (Math.Sin(dPI) * Math.Sin(dPI / (double)n)) / (dPI * (dPI / (double)n));
}
else
{
weight = 0.0;
}
//鏡像処理
if (yCurrent < 0) yCurrent *= -1;
else if (yCurrent >= h) yCurrent = 2 * h - yCurrent - 1;
if (xCurrent < 0) xCurrent *= -1;
else if (xCurrent >= w) xCurrent = 2 * w - xCurrent - 1;
// 画素取得
for (int k = 0; k < bpp; k++)
{
color_element[k] += ((double)Source[(yCurrent * stride) + xCurrent * bpp + k]) * weight;
}
w_total += weight;
}
}
for (int l = 0; l < bpp; l++)
{
if (w_total != 0.0) color_element[l] /= w_total;
color_element[l] = (color_element[l] > 255) ? 255
: (color_element[l] < 0) ? 0
: color_element[l];
colors[l] = (byte)(int)color_element[l];
}
for (int m = 0; m < bpp; m++)
{
if (y < 0 || y >= h2 || x < 0 || x >= w2) break;
Result[(y * stride2) + x * bpp2 + m] = colors[m];
}
}
});
resBmp.WritePixels(Rect, Result, stride2, 0);//WriteableBitmapに出力
return resBmp;
}

A 回答 (2件)
- 最新から表示
- 回答順に表示

No.2
- 回答日時:
ちなみに、真っ黒画像でなく、通常の写真等を縮小した場合も気になるノイズは出ますか?
ご回答ありがとうございます。
写真だと濃淡のノイズは視認できませんが、縮小がひどく汚いように感じます。
斜めの境界線が直線がつながっているような縮小画像になります。
距離計算の辺りが怪しい気がするのでコード見直してみます。

No.1
- 回答日時:
勘ですが、エイリアシングノイズじゃないですかね。
デジタル信号処理でやりませんでしたか?
縮小するということは、もともとのサンプリング間隔Δx
よりも大きいサンプリング間隔になるってことですよね。
ということは、必然的に表現できる周波数成分がF=1/2Δx
よりも減っちゃうって事ですよね。じゃあ原画像に入って
いたものもとの周波数成分の信号はどうなってしまうのか?
エイリアシングとして折り返しノイズを生むんではないで
しょうか?それが上記の紋様の正体でないかと思います。
Lanczosも畳み込み積分の一種だと思うので、エイリアシング
を生むかどうかもLanczosの周波数特性次第かなと思いました。
正しいかどうかは置いといて、それをどう対策するかが
腕の見せ所ではないでしょうか?
(勘です。ソースコードは読んでおりません。)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- FX・外国為替取引 mql4のコンパイルエラー箇所の修正お願いします。 1 2023/03/15 16:14
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語での引数の省略方法
-
「指定されたキャストは有効で...
-
#define _CRT_SECURE_NO_WARNIN...
-
未解決の外部シンボル _printf...
-
ラップ関数とはどんなものですか?
-
c言語マップ探査ゲーム プログ...
-
ヒープ木の格納 【プログラミ...
-
マルチスレッドでバグが発生します
-
入力を待たずにstdinの監視をし...
-
複数桁10進数の*桁目だけを抽出...
-
数字列を3桁ごとにカンマで区切...
-
system関数がうまくいかない
-
if と配列の組み合わせ
-
C言語 エラーの原因がわからな...
-
公約数のプログラム。
-
VB.NETからC++のdll連携(double)
-
可変長配列の初期化
-
(int *)の意味
-
アドレス型へのキャストはなぜ
-
パスカルのピラミッドを作りた...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
複数桁10進数の*桁目だけを抽出...
-
ラップ関数とはどんなものですか?
-
C言語 エラーの原因がわからな...
-
(int *)の意味
-
【C++】関数ポインタの使い方
-
if と配列の組み合わせ
-
構造体の勉強中です 合計点の高...
-
windows-findstrの正規表現を使...
-
C言語で分からないところがあり...
-
int型の変数値をバイト列として...
-
PowerShellがうまくいかない
-
C言語での奇数の和
-
「{ } で囲むだけ」は正しい?
-
std::set<int> で、ある値が何...
-
実数の整数部,小数部の取得
-
エラー 添字が付けられた値が、...
-
int16_t の _t は何?
おすすめ情報