如何解决为什么更改SDL_Surface的像素时会出现怪异的伪影?
因此,我尝试编辑SDL_Surface
的每个像素以应用灰度公式。但是,在运行代码时,我得到的是整个屏幕的宽度和weird RGB stripes填充的表面高度的区域。
void grayscale32(Uint8 *pixels,SDL_PixelFormat *format,int width,int height,int pitch) {
Uint32 *targetPixel = NULL;
Uint8 r,g,b,gray;
for (int y = 0; y * pitch < height * width * 3; y++) {
for (int x = 0; x < pitch / 4; x++) {
targetPixel = pixels + y * pitch + x * sizeof(*targetPixel);
SDL_GetRGB(*targetPixel,format,&r,&g,&b);
gray = 0.21 * r + 0.72 * g + 0.07 * b;
*targetPixel = SDL_MapRGB(format,gray,gray);
}
}
}
我想在Uint8
和Uint32
之间来回转换时是一个字节的问题,但是我不知道为什么。我尝试将Uint8 *pixels
作为Uint32 *
传递,但是它没有解决问题,并导致了分段错误。
解决方法
您有垂直条带,并且每一行都排成一行(与楼梯拼合)。因此,我相信您对3
的使用是正确的(即每个像素为3个字节)
这可能/可能是由几件事引起的。
您可能在行地址中少了一个字节。
您可能要包装/截断像素颜色值(即您需要饱和度数学)。也就是说,例如,如果您计算出的灰色灰度值为256,则它将自动将其包装/截断为0。
我认为有一种更简单的方法可以索引像素阵列。
无论如何,这是一些重构的代码。它尚未经过测试,但应该可以给您一些帮助。
我假设格式为RGB(3个字节/像素)[vs RGBA具有4个字节/像素],pitch
是每行字节的数量。
#include <SDL2/SDL.h>
typedef unsigned char Uint8;
typedef unsigned int Uint32;
static inline Uint8
grayof(Uint8 r,Uint8 g,Uint8 b)
{
Uint8 gray;
#if ORIG
gray = 0.21 * r + 0.72 * g + 0.07 * b;
#else
Uint32 acc = 0;
// use scaled integer arithmetic (vs. float)
acc += 210 * (Uint32) r;
acc += 720 * (Uint32) g;
acc += 70 * (Uint32) b;
acc /= 1000;
// saturation math
// (e.g.) prevent pixel value of 256 from wrapping to 1
if (acc > 255)
acc = 255;
gray = acc;
#endif
return gray;
}
void
grayscale32(Uint8 *pixels,SDL_PixelFormat *format,int width,int height,int pitch)
{
Uint8 *byteptr;
Uint32 *targetPixel;
Uint8 r,g,b,gray;
for (int y = 0; y < height; ++y) {
byteptr = &pixels[y * pitch];
targetPixel = (Uint32 *) byteptr;
for (int x = 0; x < width; ++x,++targetPixel) {
SDL_GetRGB(*targetPixel,format,&r,&g,&b);
gray = grayof(r,b);
*targetPixel = SDL_MapRGB(format,gray,gray);
}
}
}
没有更多信息[或原始图像],很难确切说明格式和几何形状。
虽然可能性较小,但是这里有一个替代的索引方案:
void
grayscale32(Uint8 *pixels,gray;
for (int y = 0; y < height; ++y) {
byteptr = &pixels[y * pitch];
for (int x = 0; x < width; ++x,byteptr += 3) {
targetPixel = (Uint32 *) byteptr;
SDL_GetRGB(*targetPixel,gray);
}
}
}
更新:
由于方程中的因子加起来为1,因此我认为实际上并不需要进行饱和度检查,因此即使原始值为rgb(255,255,255),我们的灰度也为255。
是的,您不需要坐式数学是正确的。我很保守[因为我懒得检查因子值:-)]。
尽管使用grayof函数,第一个仍然给了我条纹,但是第二个单独工作得很好。
好的,这意味着每个像素为3个字节[R / G / B]。我不确定是否为4字节,格式为R / G / B / A,其中A为Alpha值。
但是,鉴于内存格式为3字节/ RGB,这会带来一个问题,targetPixel
为Uint32 *
。
那是因为在执行*targetPixel = ...;
时,它存储了 4 个字节,但是循环增量为3
。这意味着给定的存储区会将一个字节渗入 next 像素区域。
这看起来像:
Memory layout:
| 0 3 6 9
| R G B | R G B | R G B | R G B |
Store progression:
| 1 2 3 | 4
| 1 2 3 | 4
| 1 2 3 | 4
| 1 2 3 | 4
因此,第二个商店实际上是 not 不能获得原始的R
值
似乎/看起来还不错,但我怀疑最终的灰度值有些偏离。
这是一个可以解决此问题的版本。如果R和B值似乎相反,则可能 需要用-DALT=1
进行编译。尝试两种方式:有/无。
#include <SDL2/SDL.h>
typedef unsigned char Uint8;
typedef unsigned int Uint32;
#ifndef ALT
#define ALT 0
#endif
enum {
#if ALT
OFF_R = 2,OFF_G = 1,OFF_B = 0,#else
OFF_R = 0,OFF_B = 2,#endif
PIXBYTES = 3
};
static inline Uint8
grayof(Uint8 r,Uint8 b)
{
Uint8 gray;
#if ORIG
gray = 0.21 * r + 0.72 * g + 0.07 * b;
#else
Uint32 acc = 0;
// use scaled integer arithmetic (vs. float)
acc += 210 * (Uint32) r;
acc += 720 * (Uint32) g;
acc += 70 * (Uint32) b;
acc /= 1000;
// saturation math
// (e.g.) prevent pixel value of 256 from wrapping to 1
#if SAT
if (acc > 255)
acc = 255;
#endif
gray = acc;
#endif
return gray;
}
void
grayscale32(Uint8 *pixels,int pitch)
{
Uint8 *byteptr;
Uint8 *bytelim;
Uint8 gray;
for (int y = 0; y < height; ++y) {
byteptr = &pixels[y * pitch];
bytelim = &byteptr[width * PIXBYTES];
for (; byteptr < bytelim; byteptr += PIXBYTES) {
gray = grayof(byteptr[OFF_R],byteptr[OFF_G],byteptr[OFF_B]);
byteptr[OFF_R] = gray;
byteptr[OFF_G] = gray;
byteptr[OFF_B] = gray;
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。