我遇到算法问题,应该模糊我的图像。 这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
return *p;
break;
case 2:
return *(Uint16 *)p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
return *(Uint32 *)p;
break;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
SDL_Surface* Filter(SDL_Surface* source)
{
SDL_Surface *target;
int x, y;
if( source->flags & SDL_SRCCOLORKEY )
{target = SDL_CreateRGBSurface( SDL_SWSURFACE, source->w ,source->h, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, 0 );}
else
{target = SDL_CreateRGBSurface( SDL_SWSURFACE, source->w ,source->h, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, source->format->Amask );}
for(y=0; y<source->h; ++y){
for(x=0; x<source->w; ++x)
{
int a = getpixel(source,x-1, y-1);
int b = getpixel(source,x , y-1);
int c = getpixel(source,x+1, y-1);
int d = getpixel(source,x-1, y);
int z = getpixel(source,x , y);
int e = getpixel(source,x+1, y);
int f = getpixel(source,x-1, y+1);
int g = getpixel(source,x , y+1);
int h = getpixel(source,x+1, y+1);
int avg = (a+b+c + d+z+e + f+g+h)/9;
putpixel(target,x, y, avg);
}
}
return target;
}
以下是过滤结果:
我不知道问题出在哪里,因为我认为模糊意味着“取9个像素,计算它们的平均值并将其放置到位”,但这不起作用。
答案 0 :(得分:1)
事情比你的代码假设要复杂一些。图像中的像素值使用特定的像素格式进行编码,因此您不能将它们相加,除以并假设一切都能正常工作。
相反,您必须分离图像的不同通道,分别对每个通道进行操作,然后再将它们分组。为此,您可以使用SDL_GetRGB()
和SDL_MapRGB()
函数:
unsigned r = 0, g = 0, b = 0;
Uint8 rt, gt, bt;
unsigned a = getpixel(source,x-1, y-1);
SDL_GetRGB(a, source->format, &rt, >, &bt);
r += rt;
g += gt;
b += bt;
//repeat for each pixel...
r /= 9;
g /= 9;
b /= 9;
unsigned avg = SDL_MapRGB(target->format, r, g, b);
PS:请注意,所有这些函数调用都会很慢。如果您事先知道像素格式,可以自己进行RGB转换。
PS2:虽然这应该或多或少有效,但请注意,如果考虑Gamma,许多颜色计算效果会更好,而不是假设颜色空间是线性的。
PS3:如果你进行两次传球,这个算法会快一个数量级。第一个将仅模糊水平边缘(3个样本),而第二个将模糊垂直边缘(3个样本)。这是O(n)
而不是O(n^2)
,是n
模糊内核的大小。
PS4:正如其他人评论的那样,你不会检查图像边界,也不会锁定表面。