2016-05-30 4 views
2

Я пытаюсь реализовать фильтр заточки матрицы свертки для изображения. Для этого я создаю матрицу 3x3. Может быть, я сделал что-то не так с формулой? Также я пробовал другую заточную матрицу, но это не помогло. Значение цвета может быть больше 255 или меньше, чем ноль, поэтому я решаю дать некоторые ограничения на это (0 255). Правильное решение?Фильтр затухания матрицы свертки

static const int filterSmallMatrixSize = 3; 
static const int sharpMatrix[3][3] = {{-1, -1, -1},{-1, 9, -1},{-1, -1, -1}}; 

некоторые определяют

#define Mask8(x) ((x) & 0xFF) 
#define R(x) (Mask8(x)) 
#define G(x) (Mask8(x >> 8)) 
#define B(x) (Mask8(x >> 16)) 
#define A(x) (Mask8(x >> 24)) 
#define RGBAMake(r, g, b, a) (Mask8(r) | Mask8(g) << 8 | Mask8(b) << 16 | Mask8(a) << 24) 

и алгоритм

- (UIImage *)processSharpFilterUsingPixels:(UIImage *)inputImage 
{ 
    UInt32 *inputPixels; 
    CGImageRef inputCGImage = [inputImage CGImage]; 
    NSUInteger inputWidth = CGImageGetWidth(inputCGImage); 
    NSUInteger inputHeight = CGImageGetHeight(inputCGImage); 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    NSUInteger bytesPerPixel = 4; 
    NSUInteger bitsPerComponent = 8; 
    NSUInteger inputBytesPerRow = bytesPerPixel * inputWidth; 
    inputPixels = (UInt32 *)calloc(inputHeight * inputWidth, sizeof(UInt32)); 
    CGContextRef context = CGBitmapContextCreate(inputPixels, inputWidth, inputHeight, 
               bitsPerComponent, inputBytesPerRow, colorSpace, 
               kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
    CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage); 

    for (NSUInteger j = 1; j < inputHeight - 1; j++) 
    { 
     for (NSUInteger i = 1; i < inputWidth - 1; i++) 
     { 
      Float32 newRedColor = 0; 
      Float32 newGreenColor = 0; 
      Float32 newBlueColor = 0; 
      Float32 newA = 0; 

      for (int filterMatrixI = 0 ; filterMatrixI < filterSmallMatrixSize ; filterMatrixI ++) 
      { 
       for (int filterMatrixJ = 0; filterMatrixJ < filterSmallMatrixSize; filterMatrixJ ++) 
       { 
        UInt32 * currentPixel = inputPixels + ((j + filterMatrixJ - 1) * inputWidth) + i + filterMatrixI - 1; 
        int color = *currentPixel; 
        newRedColor += (R(color) * sharpMatrix[filterMatrixI][filterMatrixJ]); 
        newGreenColor += (G(color) * sharpMatrix[filterMatrixI][filterMatrixJ]); 
        newBlueColor += (B(color)* sharpMatrix[filterMatrixI][filterMatrixJ]); 
        newA += (A(color) * sharpMatrix[filterMatrixI][filterMatrixJ]); 
       } 
      } 
      int r = MAX(MIN((int)newRedColor,255), 0); 
      int g = MAX(MIN((int)newGreenColor,255), 0); 
      int b = MAX(MIN((int)newBlueColor,255), 0); 
      int a = MAX(MIN((int)newA,255), 0); 
      UInt32 *currentMainImagePixel = inputPixels + (j * inputWidth) + i; 
      *currentMainImagePixel = RGBAMake(r,g,b,a); 
     } 
    } 

    CGImageRef newCGImage = CGBitmapContextCreateImage(context); 
    UIImage * processedImage = [UIImage imageWithCGImage:newCGImage]; 

    CGColorSpaceRelease(colorSpace); 
    CGContextRelease(context); 
    free(inputPixels); 

    return processedImage; 
} 

В результате у меня есть этот this

+1

«Может, я сделал что-то не так с формулой?» - Не уверен. Разве вы не намеревались этого эффекта? Я думаю, это выглядит довольно интересно. Во всяком случае, не спам языковые теги! – Olaf

+1

Не просто скопируйте значения цвета в соответствии с вашими границами и скорее масштабируйте их. С данной матрицей вы можете получить значения в диапазоне от -2040 до 2295. Зная это и тот факт, что все значения цвета могут быть между 0 и 255, вы можете использовать этот формуляр для масштабирования значений и, таким образом, сохранить объем информации: y = (x + 2040)/(2295 + 2040) * (255 - 0) + 0', с 'x' отфильтрованных значений и' y' ваше новое значение цвета от 0 до 255. (Общий формуляр для преобразования x от [a, b] до y в [c, d] есть 'y = (x - a)/(ba) * (dc) + c)') – muXXmit2X

+0

@Olaf Предположим, что это «резкий» эффект :(I добавили эти теги, потому что это немного c и C++. Извините. –

ответ

1

Рассмотрим эти пиксели в середине изображения:

|_|_|_|_| 
|_|_|_|_| 
|_|_|_|_| 
|_|_|_|_| 

Поскольку вы обновляете изображение на месте, это то, как он выглядит где-то в середине цикла точит:

|u|u|u|u| 
|u|u|u|u| 
|u|c|_|_| 
|_|_|_|_| 

u Где обозначает обновленный пиксель, c для тока. Таким образом, его новый цвет зависит от цвета объемных пикселей, половина из которых от уже заточенного изображения, половина от начала. Чтобы исправить это нам нужно копию пикселов исходного изображения:

... 
CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage); 

UInt32 *origPixels = calloc(inputHeight * inputWidth, sizeof(UInt32)); 
memcpy(origPixels, inputPixels, inputHeight * inputWidth * sizeof(UInt32)); 

for (NSUInteger j = 1; j < inputHeight - 1; j++) { 
... 

И теперь нам нужно изменить только одну строку, чтобы получить наши текущие пиксели исходного изображения

//changed inputPixels -> origPixels 
UInt32 * currentPixel = origPixels + ((j + filterMatrixJ - 1) * inputWidth) + i + filterMatrixI - 1; 

Here are some примеры того, как он работает по сравнению к не обновленному фильтру (ссылка - это Dropbox, извините за это). Я пробовал разные матрицы, а так же для меня лучше было где-то около

const float sharpMatrix[3][3] = {{-0.3, -0.3, -0.3},{-0.3, 3.4, -0.3},{-0.3, -0.3, -0.3}} 

Кроме того, я должен заметить, что этот способ сохранения исходного изображения не является оптимальным. Мое исправление в основном удваивает объем потребляемой памяти. Это можно легко сделать, удерживая только две линии пикселей, и я уверен, что есть еще лучшие способы.

Смежные вопросы