2013-12-19 1 views
0

CIMedianFilter는 어떻게 작동합니까? 나는 그것을위한 알고리즘을 의미하고, 나는 잡음 제거를 원한다. 나는이 코드로 그것을 시도했다 :CIMedianFilter는 어떻게 작동합니까? (알고리즘)

   // -------------------------- W O R K I N G O N R E D ----------------- 
       // red pixels 
       NSNumber *red1 = [NSNumber numberWithInt:rgbaPixel1[3]]; 
       NSNumber *red2 = [NSNumber numberWithInt:rgbaPixel2[3]]; 
       NSNumber *red3 = [NSNumber numberWithInt:rgbaPixel3[3]]; 
       NSNumber *red4 = [NSNumber numberWithInt:rgbaPixel4[3]]; 
       NSNumber *red5 = [NSNumber numberWithInt:rgbaPixel5[3]]; 

       // red array 
       NSMutableArray *redArray = [NSMutableArray arrayWithObjects:red1, red2, red3, red4, red5, nil]; 
       // sorting 
       NSSortDescriptor *lowToHigh = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES]; 
       [redArray sortUsingDescriptors:[NSArray arrayWithObject:lowToHigh]]; 
       // getting median 
       int redMedian = [[redArray objectAtIndex:2] intValue]; 
       // setting the pixels red value to the median 
       rgbaPixel1[3] = redMedian; 
       /////////////////////////////////testing if sorting and median is true 
       //   NSLog(@"Sir, here's a test (%@, %@, %@, %@, %@) and the median is %i", [redArray objectAtIndex:0], 
       //                     [redArray objectAtIndex:1], 
       //                     [redArray objectAtIndex:2], 
       //     [redArray objectAtIndex:3], [redArray objectAtIndex:4], shit); 
       // ---------------------------- E N D O F R E D ------------------------ 

       // ----------------------------- W O R K I N G O N G R E E N --------------- 
       // getting green pixels first 
       NSNumber *green1 = [NSNumber numberWithInteger:rgbaPixel1[2]]; 
       NSNumber *green2 = [NSNumber numberWithInteger:rgbaPixel2[2]]; 
       NSNumber *green3 = [NSNumber numberWithInteger:rgbaPixel3[2]]; 
       NSNumber *green4 = [NSNumber numberWithInteger:rgbaPixel4[2]]; 
       NSNumber *green5 = [NSNumber numberWithInteger:rgbaPixel5[2]]; 

       // creating array of greens 
       NSMutableArray *greenArray = [NSMutableArray arrayWithObjects:green1, green2, green3, green4, green5, nil]; 
       // sorting the array 
       [greenArray sortUsingDescriptors:[NSArray arrayWithObject:lowToHigh]]; 
       // getting the median 
       int greenMedian = [[greenArray objectAtIndex:2] intValue]; 

       // setting the pixels green value to median value 
       rgbaPixel1[2] = greenMedian; 
       // ---------------------------- E N D O F G R E E N ------------------------ 

       // -------------------------- W O R K I N G O N B L U E --------------------- 
       // getting blue pixel 
       NSNumber *blue1 = [NSNumber numberWithInteger:rgbaPixel1[1]]; 
       NSNumber *blue2 = [NSNumber numberWithInteger:rgbaPixel2[1]]; 
       NSNumber *blue3 = [NSNumber numberWithInteger:rgbaPixel3[1]]; 
       NSNumber *blue4 = [NSNumber numberWithInteger:rgbaPixel4[1]]; 
       NSNumber *blue5 = [NSNumber numberWithInteger:rgbaPixel5[1]]; 

       // creating array for blue values 
       NSMutableArray *blueArray = [NSMutableArray arrayWithObjects:blue1, blue2, blue3, blue4, blue5, nil]; 
       // sorting the array of blues 
       [blueArray sortUsingDescriptors:[NSArray arrayWithObject:lowToHigh]]; 
       // getting the median 
       int blueMedian = [[blueArray objectAtIndex:2] intValue]; 


       // setting pixel blue value to the median we just got :) 
       rgbaPixel1[1] = blueMedian; 

       // --------------------------------- E N D O F B L U E ---------------------- 

그러나 그다지 효과가 없다! 또는 어쩌면 내가 RGB 값을 잘못된 방법으로 가져 오는 중, 정말이 일부 도움이 필요합니다.

답변

2

CIMedianFilter에 대해서는 말할 수 없습니다. 코어 이미지의 특징을 모르지만 GPUImage 프레임 워크에 대한 중간 값 필터를 작성 했으므로 그 과정을 설명 할 수 있습니다.

먼저, NSNumber 및 NSMutableArray의 무거운 객체를 사용하여 위에서 수행 한 작업은 이미지의 픽셀을 반복 할 때 성능이 현저하게 떨어질 것이라고 말합니다. 또한 자동 복구 된 모든 객체의 메모리 관리가 까다로울 수 있습니다. 이것을 위해서는 적어도 스칼라 유형과 C 배열로 이동하고 정렬을 위해 인라인 함수를 사용해야합니다. 더 나은 방법은 GPU로 마이그레이션하는 것입니다.

GPUImage에있는 GPU 기반 구현은 ShaderX6의 Morgan McGuire 및 Kyle Whitson의 "A Fast, Small-Radius GPU Median Filter" 장을 기반으로합니다. 이 글에서는 프래그먼트 셰이더에서 GPU 측 중앙 필터링을 가속화하는 데 사용할 수있는 몇 가지 최적화에 대해 설명합니다. 프래그먼트 쉐이더 내에서 3 × 3 중간 값 필터의 내 구현은 다음과 같습니다

precision highp float; 

varying vec2 textureCoordinate; 
varying vec2 leftTextureCoordinate; 
varying vec2 rightTextureCoordinate; 

varying vec2 topTextureCoordinate; 
varying vec2 topLeftTextureCoordinate; 
varying vec2 topRightTextureCoordinate; 

varying vec2 bottomTextureCoordinate; 
varying vec2 bottomLeftTextureCoordinate; 
varying vec2 bottomRightTextureCoordinate; 

uniform sampler2D inputImageTexture; 

#define s2(a, b)    temp = a; a = min(a, b); b = max(temp, b); 
#define mn3(a, b, c)   s2(a, b); s2(a, c); 
#define mx3(a, b, c)   s2(b, c); s2(a, c); 

#define mnmx3(a, b, c)   mx3(a, b, c); s2(a, b);         // 3 exchanges 
#define mnmx4(a, b, c, d)  s2(a, b); s2(c, d); s2(a, c); s2(b, d);     // 4 exchanges 
#define mnmx5(a, b, c, d, e) s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e);   // 6 exchanges 
#define mnmx6(a, b, c, d, e, f) s2(a, d); s2(b, e); s2(c, f); mn3(a, b, c); mx3(d, e, f); // 7 exchanges 

void main() 
{ 
    vec3 v[6]; 

    v[0] = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb; 
    v[1] = texture2D(inputImageTexture, topRightTextureCoordinate).rgb; 
    v[2] = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb; 
    v[3] = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb; 
    v[4] = texture2D(inputImageTexture, leftTextureCoordinate).rgb; 
    v[5] = texture2D(inputImageTexture, rightTextureCoordinate).rgb; 
//  v[6] = texture2D(inputImageTexture, bottomTextureCoordinate).rgb; 
//  v[7] = texture2D(inputImageTexture, topTextureCoordinate).rgb; 
    vec3 temp; 

    mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]); 

    v[5] = texture2D(inputImageTexture, bottomTextureCoordinate).rgb; 

    mnmx5(v[1], v[2], v[3], v[4], v[5]); 

    v[5] = texture2D(inputImageTexture, topTextureCoordinate).rgb; 

    mnmx4(v[2], v[3], v[4], v[5]); 

    v[5] = texture2D(inputImageTexture, textureCoordinate).rgb; 

    mnmx3(v[3], v[4], v[5]); 

    gl_FragColor = vec4(v[4], 1.0); 
} 

이 iOS 기기에 라이브 비디오에 대해 실행 충분히 빠르지 만 3 × 3 반경이 볼하지 않는 것이 충분히 작은 최종 이미지의 극적인 변화. 소량의 공간 노이즈 제거 기능을 제공하지만 더 극적인 노이즈 제거 효과를 보려면 5x5 영역으로 확장해야 할 수도 있습니다. 그러면 이미지가 약간 흐려지기 시작합니다. 따라서 약간의 트레이드 오프가 있습니다. 비디오를 사용하면 약간의 일시적인 노이즈 제거 작업을 수행하기 위해 더 낮은 강도의 필터로 이것을 연결할 수 있습니다.

위의 용지를 3x3보다 큰 경우에 적용 할 수있는 운동으로 남겨 두겠습니다.

0

는 OpenGL ES 코드 3.0 대안은 위의 다음 : 당신이 볼 수 있듯이

kernel vec4 medianUnsharpKernel(sampler u) { 
vec4 pixel = unpremultiply(sample(u, samplerCoord(u))); 
vec2 xy = destCoord(); 
int radius = 3; 
int bounds = (radius - 1)/2; 
vec4 sum = vec4(0.0); 
for (int i = (0 - bounds); i <= bounds; i++) 
{ 
    for (int j = (0 - bounds); j <= bounds; j++) 
    { 
     sum += unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j))))); 
    } 
} 
vec4 mean = vec4(sum/vec4(pow(float(radius), 2.0))); 
float mean_avg = float(mean); 
float comp_avg = 0.0; 
vec4 comp = vec4(0.0); 
vec4 median = mean; 
for (int i = (0 - bounds); i <= bounds; i++) 
{ 
    for (int j = (0 - bounds); j <= bounds; j++) 
    { 
     comp = unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j))))); 
     comp_avg = float(comp); 
     median = (comp_avg < mean_avg) ? max(median, comp) : median; 
    } 
} 

return premultiply(vec4(vec3(abs(pixel.rgb - median.rgb)), 1.0)); 
} 

, 이것은 OpenGL을의 하위 집합을 사용하여 오래된 장치와 호환성이다; 그리고 나는 아마도 더 빨리 달릴 것이라고 믿는다 (더 짧다). 아마도 첫 번째 패스의 픽셀 값을 배열에 저장 한 다음 배열의 두 번째 패스를 호출하여 속도를 배가시킬 수 있습니다.

기본적으로 두 단계로 구성되어 있으므로 이해하기가 더 쉽습니다. 1. 3x3 근방에서 소스 픽셀을 둘러싼 픽셀 값의 평균을 계산하십시오. 2. 같은 이웃에서 평균보다 작은 모든 픽셀의 최대 픽셀 값을 찾습니다. 3. [선택 사항] 가장자리 감지를 위해 원본 픽셀 값에서 중간 픽셀 값을 뺍니다.

가장자리 감지에 중간 값을 사용하는 경우 위의 코드를 수정하여 하이브리드 중간 필터링 및 잘린 미디어 필터링 (더 나은 '모드'필터링). 관심이 있으시면, 물어보십시오.

+0

평균으로부터 평균을 계산하는 알고리즘을 이해할 수 없습니다. 배열 (0, 100, 100)의 경우 평균은 67이고 가장 큰 값은 67이며 중앙값이 아닙니다. –

+0

Brad Larson의 필터를 정확하게 복사했습니다. 수학이 합쳐지지 않으면 나를 보지 마라.평균 (?)에서 중간 값을 계산하는 방법을 알려주는 백만 개의 웹 사이트가 있습니다. 필요한 경우, 귀하의 필요에 따라 그것들을 참조하십시오. –

관련 문제