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.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ランキング
-
比較回数と交換回数表示について
-
nCmの関数
-
複数桁10進数の*桁目だけを抽出...
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 配列と関数の練習問題
-
c言語
-
std::set<int> で、ある値が何...
-
卒業研究でよく分からないとこ...
-
C言語 エラーの原因がわからな...
-
DLLをGetProcAddress()で実行で...
-
【C++】関数ポインタの使い方
-
read関数をノンブロッキングで...
-
C言語における対称行列の作り方...
-
構造体の勉強中です 合計点の高...
-
C言語です。
-
C言語での引数の省略方法
-
困ってます…nCrを求めるC言語...
-
C++でvectorにテキストファイル...
-
プログラミング
-
素数 再帰関数
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
「指定されたキャストは有効で...
-
C言語 配列と関数の練習問題
-
複数桁10進数の*桁目だけを抽出...
-
(int *)の意味
-
if と配列の組み合わせ
-
ラップ関数とはどんなものですか?
-
卒業研究でよく分からないとこ...
-
【C++】関数ポインタの使い方
-
c言語
-
足して100になるような乱数のア...
-
C言語初心者です、、、お助けく...
-
数字列を3桁ごとにカンマで区切...
-
C言語 エラーの原因がわからな...
-
実数の整数部,小数部の取得
-
課題でつまってます・・・
-
商と剰余を同時に求める(C言語)
-
C言語の配列をC++のvectorに高...
-
std::set<int> で、ある値が何...
おすすめ情報