2013-01-16 3 views
1

색조, 채도 및 밝기 값을 높이거나 낮추기 위해 비트 맵 이미지를 필터링하려고합니다.비트 맵에서 색조/채도/밝기를 변경하는 더 빠른 알고리즘

내 코드는 완벽하게 작동하지만 은 느림입니다.

원본 소스와 현재 대상의 두 비트 맵을 메모리에 잠급니다. 사용자는 다양한 트랙 바 컨트롤을 이동하여 각 값을 수정 한 다음 HSL 값으로 변환 할 수 있습니다. 예를 들어, 트랙 바의 값은 -1.0에서 1.0의 범위에 해당합니다.

트랙바 값이 변경된 이벤트가 발생할 때마다 대상 비트 맵을 잠그고 원본 비트 맵에 HSL 값을 적용한 다음 결과를 대상 비트 맵에 저장합니다. 끝나면 대상 비트 맵의 ​​잠금을 해제하고 이미지를 화면에 페인트합니다.

이전에는 바이트 단위 작업을 수행 한 이후 조회 표을 다른 필터에 사용했습니다. 그러나 나는 HSL을 대신 사용하는 방법을 모릅니다. 여기에 내가 사용하고있는 코드입니다 :

byte red, green, blue; 

for (int i = 0; i < sourceBytes.Length; i += 3) 
{ 
    blue = sourceBytes[i]; 
    green = sourceBytes[i + 1]; 
    red = sourceBytes[i + 2]; 

    Color newColor = Color.FromArgb(red, green, blue); 

    if (ModifyHue) 
     newColor = HSL.ModifyHue(newColor, Hue); 

    if (ModifySaturation) 
     newColor = HSL.ModifySaturation(newColor, Saturation); 

    if (ModifyLightness) 
     newColor = HSL.ModifyBrightness(newColor, Lightness); 

    destBytes[i] = newColor.B; 
    destBytes[i + 1] = newColor.G; 
    destBytes[i + 2] = newColor.R; 
} 

는 그리고 여기 내 ModifyBrightness 기능입니다 : 자신의 밝기 슬라이더가 매우 중간에있는 경우, 그 값은 내가로 변환됩니다 0입니다 그래서 기본적으로

public static Color ModifyBrightness(Color color, double brightness) 
{ 
    HSL hsl = FromRGB(color); 
    hsl.L *= brightness; 
    return hsl.ToRGB(); 
} 

"1.0"을 함수에 전달하면 밝기에 1.0이 곱해 지므로 변경되지 않습니다. 슬라이더를 오른쪽으로 드래그하면 값이 100이되어 2.0의 수식자가됩니다. 따라서 밝기 값에 2.0을 곱하여 곱합니다.

+1

우선 캐시 결과, 그리고 빨리 배열에 액세스하기위한 안전하지 않은 코드를 사용합니다. – SimpleVar

+0

+1. 그런 마이크로 코드를 사용하면 어레이 액세스가 완전히 당신을 죽입니다. 모든 액세스는 최소값/최대 값에 대한 검사입니다. 안전하지 않은 포인터 코드를주세요. 동시에 모든 값을 가진 바이트에서 struct로 이동하십시오. – TomTom

+0

혹시이 문서화 된 참고 자료가 있습니까? Afaik 배열 구문은 배열이 포인터 일 때 포인터 구문과 동일합니까? 어쨌든 최대/최소 한계는 없습니다. – Rotem

답변

4

내가 연구 ImageAttributes를 종료하고 ColorMatrix 및 성능이 우수했다 발견했다. 여기

내가 채도 및 밝기 필터를 구현하는 방법입니다 : 내가 할 것

// Luminance vector for linear RGB 
const float rwgt = 0.3086f; 
const float gwgt = 0.6094f; 
const float bwgt = 0.0820f; 

private ImageAttributes imageAttributes = new ImageAttributes(); 
private ColorMatrix colorMatrix = new ColorMatrix(); 
private float saturation = 1.0f; 
private float brightness = 1.0f; 

protected override void OnPaint(object sender, PaintEventArgs e) 
{ 
    base.OnPaint(sender, e); 

    e.Graphics.DrawImage(_bitmap, BitmapRect, BitmapRect.X, BitmapRect.Y, BitmapRect.Width, BitmapRect.Height, GraphicsUnit.Pixel, imageAttributes); 
} 

private void saturationTrackBar_ValueChanged(object sender, EventArgs e) 
{ 
    saturation = 1f - (saturationTrackBar.Value/100f); 

    float baseSat = 1.0f - saturation; 

    colorMatrix[0, 0] = baseSat * rwgt + saturation; 
    colorMatrix[0, 1] = baseSat * rwgt; 
    colorMatrix[0, 2] = baseSat * rwgt; 
    colorMatrix[1, 0] = baseSat * gwgt; 
    colorMatrix[1, 1] = baseSat * gwgt + saturation; 
    colorMatrix[1, 2] = baseSat * gwgt; 
    colorMatrix[2, 0] = baseSat * bwgt; 
    colorMatrix[2, 1] = baseSat * bwgt; 
    colorMatrix[2, 2] = baseSat * bwgt + saturation; 

    imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

    Invalidate(); 
} 

private void brightnessTrackBar_ValueChanged(object sender, EventArgs e) 
{ 
    brightness = 1f + (brightnessTrackBar.Value/100f); 

    float adjustedBrightness = brightness - 1f; 

    colorMatrix[4, 0] = adjustedBrightness; 
    colorMatrix[4, 1] = adjustedBrightness; 
    colorMatrix[4, 2] = adjustedBrightness; 

    imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

    Invalidate(); 
} 
+1

재미있는 부분은 개별 행렬을 사용하여 여러 가지 효과를 계산할 수 있고 행렬을 곱하여 효과를 결합하는 것입니다. – Rotem

1

앱을 프로필하고 문제가있는 곳을 확인해야합니다.

임의의 제안 :

  • 사용하는 32 비트 당 픽셀 형식은 정렬되지 않은 읽기 방지 할 수 있습니다. (단일 작업으로 전체 (32)를 읽기)
  • 피하기 여러 RGB < -> HSL 변환
+0

글쎄, 대비, RGB 밝기, 감마, 반전 등 동일한 코드를 사용합니다. 그리고 그것은 매우 빠릅니다. 따라서 RGB/HSL 변환이 주요 초크 포인트입니다. 어쩌면 당신은 내가 여러 번의 회심을 피하는 방법을 상세히 설명 할 수 있습니다. 내가 조회 테이블을 사용하여 생각하지만 어떻게 LUT를 이중 값으로 사용할 수 있습니까? 바이트 값을 사용하면 256 가지 가능성이 있기 때문에 쉽습니다. –

+0

@Moozhe, 코드는 2 개의 쓸모없는 변형을 시작합니다 (H S L을 모두 변경해야하는 경우). 그렇지 않으면 -'FromRGB' 코드를보고 최적화하십시오. 최악의 경우 미리 계산 된 테이블에 대한 정수 값의 16M은 세계에서 끝나지 않습니다 ... –

+0

@AlexeiLevenkov 실제로 16.7m 색상 * 4 바이트 = 67MB로 매우 적합하지는 않습니다. 말할 것도없이 이미지에 실제로 존재하는 값보다 더 많은 값을 가지기 때문에 LUT 생성을 계산보다 느리게 만듭니다. – Rotem

관련 문제