NTSC信号処理で画像をフィルタリングするC++で書かれたライブラリが見つかりました。あなたはここにそれを見ることができます:http://slack.net/~ant/libs/ntsc.html#nes_ntsc目的は、テレビにNESによって出力されたように画像を見せることです。C#画像データを複雑にする - 複雑なシナリオ
ライブラリのSNESバージョンをC#でラップしたい(実際にはNESバージョンを使用しますが、NTSCパレットデータのみで動作し、ビットマップは使用しません)。数時間コードを再生した後、敗北を認めて、皆さんに助けを求めてください。
ライブラリのC++コードを次に示します。私はdllexportsを追加しました。
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct snes_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
__declspec(dllexport) void snes_ntsc_init(snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup);
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */
__declspec(dllexport) void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch);
ここでは、C++デモコードのスニペットを示します。それはSDLを使用します。
typedef struct image_t
{
unsigned char const* byte_pixels;/* 8-bit pixels */
unsigned short const* rgb_16; /* 16-bit pixels */
int width;
int height;
int row_width; /* number of pixels to get to next row (may be greater than width) */
} image_t;
image_t image;
int burst_phase = 0;
snes_ntsc_setup_t setup = snes_ntsc_composite;
snes_ntsc_t* ntsc = (snes_ntsc_t*) malloc(sizeof (snes_ntsc_t));
if (!ntsc)
fatal_error("Out of memory");
snes_ntsc_init(ntsc, &setup);
load_bmp(&image, (argc > 1 ? argv [1] : "test.bmp"), 0);
init_window(SNES_NTSC_OUT_WIDTH(image.width), image.height * 2);
// lock the SDL image surface elsewhere...
output_pitch = surface->pitch;
output_pixels = (unsigned char*) surface->pixels;
burst_phase = 0;
snes_ntsc_blit(ntsc, image.rgb_16, image.row_width, burst_phase,
image.width, image.height, output_pixels, output_pitch);
SNES_NTSC_OUT_WIDTHを使用すると、入力256
さらに、ライブラリは6 5 6において、内外両方のピクセル当たり16ビットで動作するように(デフォルトで)内蔵されている場合441を返すマクロですパターン。
、ドキュメントから、このデータのすべてを定義し使用して、とのtypedef、ここでのC#のいくつかで私の試みです:
[DllImport("snes.dll")]
internal static extern void snes_ntsc_init(snes_ntsc_t t, snes_ntsc_setup_t setup);
[DllImport("snes.dll")]
internal static extern void snes_ntsc_blit(snes_ntsc_t ntsc, IntPtr input,
long in_row_width, int burst_phase, int in_width, int in_height,
[Out]IntPtr rgb_out, [Out]long out_pitch);
[StructLayout(LayoutKind.Sequential)]
internal class snes_ntsc_t
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (0x2000 * 128))]
public ulong[] table;
}
[StructLayout(LayoutKind.Sequential)]
internal struct snes_ntsc_setup_t
{
/* Basic parameters */
public double hue; /* -1 = -180 degrees +1 = +180 degrees */
public double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
public double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
public double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
public double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
public double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
public double resolution; /* image resolution */
public double artifacts; /* artifacts caused by color changes */
public double fringing; /* color artifacts caused by brightness changes */
public double bleed; /* color bleed (color resolution reduction) */
public int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
public float decoder_matrix; /* optional RGB decoder matrix, 6 elements */
public ulong bsnes_colortbl; /* undocumented; set to 0 */
}
// Inside my main function...
snes_ntsc_t t = new snes_ntsc_t();
t.table = new ulong[0x2000 * 128];
snes_ntsc_setup_t setup = new snes_ntsc_setup_t();
setup.merge_fields = 1;
snes_ntsc_init(t, setup);
Bitmap orig = (Bitmap)Bitmap.FromFile("test.png");
Bitmap image = new Bitmap(orig.Width, orig.Height, PixelFormat.Format16bppRgb565);
using (Graphics g = Graphics.FromImage(image)) g.DrawImage(orig, new Rectangle(0, 0, orig.Width, orig.Height));
orig.Dispose();
BitmapData bits = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppRgb565);
// this image size is given in the demo
Bitmap output = new Bitmap(441, 448);
BitmapData outbits = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb565);
IntPtr outscan = Marshal.AllocHGlobal(outbits.Height * outbits.Width * 2);
snes_ntsc_blit(t, bits.Scan0, bits.Stride, 0, bits.Width, bits.Height, outscan, outbits.Stride);
// copy back to Scan0, if that's correct. Help with that too?
image.UnlockBits(bits);
ので、問題はsnes_ntsc_blit
ラインで、私が得るということですAccessViolationExceptionこの素晴らしく役に立たないエラーは基本的にセグメンテーション違反ですが、私は私が作った可能性ミスの数十のは考えていません:
- が誤って割り当てられた私の
snes_ntsc_t
テーブルですが?私はそれのためにマーシャルを使うべきでしょうか? - 私の画像サイズ(602x448)は間違っていますか?あまりにも大きすぎるとこのエラーが出るのですか、それともそれをエラーとして排除する可能性がありますか?
- 私の構造体宣言は正しいですか?タイプが間違っていたり、他のものがパラメータから外れる必要がある場合、マーシャリングが必要なものがあるかどうかは分かりません。
- 私のblitパラメータは正しいですか?私は本当に考えていないが、それは尋ねられているものと一致するようだ。
- ビットマップデータを何とか整列化する必要がありますか?もしそうなら、説明してください。
私はこのような大きな質問を投稿して申し訳ありませんが、マーシャリングは私のC#キャリアの悩みです。私はそれが嫌いです。助けてください。
編集
私は内にブレークポイントを入れて、Cのコードにステップすることができました。 initコールの私のパラメータは今はokですが、blit
の場合、私の入力パラメータはすべて乱れています。 VS(C側)にそれを載せて、アドレスのように見えるものとユニコードのゴミを表示します。これが大丈夫かどうかわかりません。エラーは、内部forループのSNES_NTSC_RGB_OUT行中に発生しますが、最初のパスでは発生しません。前記マクロは数学を行い、次に第2パラメータに代入する。だからここブリット関数のコードは次のとおりです。
void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch)
{
int chunk_count = (in_width - 1)/snes_ntsc_in_chunk;
for (; in_height; --in_height)
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW(ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN(*line_in));
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for (n = chunk_count; n; --n)
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN(0, SNES_NTSC_ADJ_IN(line_in [0]));
SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_COLOR_IN(1, SNES_NTSC_ADJ_IN(line_in [1]));
SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_COLOR_IN(2, SNES_NTSC_ADJ_IN(line_in [2]));
SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN(0, snes_ntsc_black);
SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_COLOR_IN(1, snes_ntsc_black);
SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_COLOR_IN(2, snes_ntsc_black);
SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
多分私RGB_OUTパラメータはまだもそれに私の[出力]で、適切に整列化されていませんか?または、私はいくつかのサイズを間違って計算しているのでしょ繰り返しになりますが、膨大な量のコードには謝罪します。
ありがとう!あなたがそうするまで、私は実際にはアンマネージコードでブレークポイントを実行していませんでした。私のinitはうまく見えますが、私のblitのparamsはもう一方の側でゴミに見えます。編集を参照してください。 – Tesserex
私はそれを修正しました - 私のマーシャリングは良かった、それは悪い私の主張でした。しかし、私のバージョンとCのデモを並べて、それを理解するのを助けました。ありがとう! – Tesserex
クール。あなたがうまく働いてうれしいです:-) –