C#编组图像数据-复杂场景 我找到了一个用C++编写的库,用NTSC信号处理来过滤图像。你可以在这里看到:其目的是使图像看起来像是NES输出到电视上的图像
我想用C#包装SNES版本的库(实际上,我会使用NES版本,但它只适用于NTSC调色板数据,而不适用于位图)。在玩了几个小时的代码后,我承认失败了,并向大家寻求帮助C#编组图像数据-复杂场景 我找到了一个用C++编写的库,用NTSC信号处理来过滤图像。你可以在这里看到:其目的是使图像看起来像是NES输出到电视上的图像,c#,bitmap,marshalling,C#,Bitmap,Marshalling,我想用C#包装SNES版本的库(实际上,我会使用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 ver
这里是库中的一些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\u NTSC\u OUT\u WIDTH是一个宏,如果输入256,则返回441
此外,该库(默认情况下)构建为在6-5-6模式下,每像素16位输入和输出
使用来自docs、defines和typedefs的所有这些数据,下面是我对一些C#的尝试:
所以,问题是在snes\u ntsc\u blit
行上,我得到了一个AccessViolationException。这个毫无帮助的错误基本上是一个segfault,但我不知道我犯了几十个可能的错误中的哪一个:
snes\u ntsc\t
表是否分配错误?也许我应该找警察来blit
,我的输入参数都搞乱了。在VS中(在C端)将鼠标移到它上面,显示一个地址和一些unicode垃圾。我不知道这是否合适。该错误发生在内部for循环的SNES_NTSC_RGB_OUT行中,但不是在第一次通过时。所述宏进行一系列运算,然后分配给第二个参数。下面是blit函数的代码:
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参数仍然没有正确编组,即使我的[out]在上面?或者我计算错了一些尺寸?再次为大量的代码表示歉意。在C中,
无符号长
是一个32位无符号整数——它对应于C#中的uint
,而不是ulong
,它是一个64位无符号整数。因为这个结构是按值传递的,所以您可能向函数传递了太多的数据,并用图像数据来替换其余的参数。更改C#绑定中的snes\u ntsc\t
定义,以包含uint[]
,然后查看发生了什么
(您在其他一些地方也犯了同样的错误。您可能会查看
long
类型的所有定义,并仔细检查C类型。Clong
将是32位的,对应于C的int
,而Clong
将是64位的,对应于C的long
)我认为你的问题可以追溯到你打电话给snes\U ntsc\U init。我通过在C++(32位)和C客户端中使用代码编写一个非托管DLL来模拟它。在DLL中,函数snes_ntsc_init和snes_ntsc_blit什么都不做——我只是在它们上面放了一个断点,看看封送的参数有什么值
这是我在snes_ntsc_init中发现的:
第二个参数“setup”是一个struct*。因此,您必须在C#端将其作为“ref setup”传递
我在C#结构定义中的每个结构成员上放置了MarshalAs属性,以确保大小正确。我的DLL是32位的,但你的可能是64位的。这就是我在C#中定义结构的方式:
解码器_矩阵是浮点*,而不是浮点。(要么是打字错误,要么就是代码盲……很容易犯这种错误。)此外,由于它是指针,你必须使用不安全的代码来初始化它,或者类似的东西。在我的测试中,我只是将其设置为IntPtr.Zero
这就是我从C#调用函数的方式:
在调试器的DLL中,我可以看到“setup”参数包含这些值。这意味着它被正确地编组。不一定独立于体系结构,因为其中可能还有一些隐含的大小假设,但至少这是一个开始
我认为现在回答你的其他问题还为时过早。我建议您像我一样构建一个存根DLL,至少让所有参数都正确编组。然后你就可以担心语义了
祝你好运!谢谢你提出了一个有趣的问题:-)谢谢你的更正,但它还是坏了。可能有很多问题,谢谢!在您这样说之前,我实际上没有在非托管代码中设置断点。我的头看起来很好,但另一边我的布利特情人看起来很邋遢。请参阅编辑。我修复了它-我的编组很好,只是我的参数不好。但是,我的版本和C演示程序并排进行,帮助我解决了这个问题。谢谢
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;
}
}
[DllImport("snes_server.dll")]
internal static extern
void snes_ntsc_init(snes_ntsc_t t, ref snes_ntsc_setup_t setup);
[StructLayout(LayoutKind.Sequential)]
internal struct snes_ntsc_setup_t
{
[MarshalAs(UnmanagedType.R8)] public double hue;
[MarshalAs(UnmanagedType.R8)] public double saturation;
[MarshalAs(UnmanagedType.R8)] public double contrast;
[MarshalAs(UnmanagedType.R8)] public double brightness;
[MarshalAs(UnmanagedType.R8)] public double sharpness;
[MarshalAs(UnmanagedType.R8)] public double gamma;
[MarshalAs(UnmanagedType.R8)] public double resolution;
[MarshalAs(UnmanagedType.R8)] public double artifacts;
[MarshalAs(UnmanagedType.R8)] public double fringing;
[MarshalAs(UnmanagedType.R8)] public double bleed;
[MarshalAs(UnmanagedType.I4)] public int merge_fields;
[MarshalAs(UnmanagedType.SysInt)] public IntPtr decoder_matrix;
[MarshalAs(UnmanagedType.SysInt)] public IntPtr bsnes_colortbl;
}
snes_ntsc_setup_t setup = new snes_ntsc_setup_t();
setup.merge_fields = 1;
setup.hue = 0.1;
setup.saturation = 0.2;
setup.contrast = 0.3;
setup.brightness = 0.4;
setup.sharpness = 0.5;
setup.gamma = 0.6;
setup.artifacts = 0.7;
setup.fringing = 0.8;
setup.bleed = 0.9;
setup.merge_fields = 10;
setup.decoder_matrix = IntPtr.Zero;
setup.bsnes_colortbl = IntPtr.Zero;
snes_ntsc_init(t, ref setup);