Retinex 알고리즘 구현
-
20-12-2019 - |
문제
구현해야 해요 단일 스케일 레티넥스 및 다중 스케일 레티넥스 알고리즘 C#에서는
조금 검색했지만 코드가 포함된 유용한 연습 프로젝트와 기사를 찾을 수 없습니다.
내가 올바르게 이해한 대로 다음을 수행해야 합니다.
- RGB를 YUV로 변환
- 가우시안 흐림 필터를 사용하여 이미지를 흐리게 합니다.
- I'(x, y) = 255*log10( I(x, y)/G(x, y) ) + 127.5를 사용하세요.
I - 조명, G - 가우스 커널, I' - 결과 이미지 - YUV를 RGB로 다시 변환
이 코드는 올바르게 작동하지 않습니다
public static Image<Bgr, byte> SingleScaleRetinex(this Image<Bgr, byte> img, int gaussianKernelSize, double sigma)
{
var radius = gaussianKernelSize / 2;
var kernelSize = 2 * radius + 1;
var ycc = img.Convert<Ycc, byte>();
var sum = 0f;
var gaussKernel = new float[kernelSize * kernelSize];
for (int i = -radius, k = 0; i <= radius; i++, k++)
{
for (int j = -radius; j <= radius; j++)
{
var val = (float)Math.Exp(-(i * i + j * j) / (sigma * sigma));
gaussKernel[k] = val;
sum += val;
}
}
for (int i = 0; i < gaussKernel.Length; i++)
gaussKernel[i] /= sum;
var gray = new Image<Gray, byte>(ycc.Size);
CvInvoke.cvSetImageCOI(ycc, 1);
CvInvoke.cvCopy(ycc, gray, IntPtr.Zero);
// Размеры изображения
var width = img.Width;
var height = img.Height;
var bmp = gray.Bitmap;
var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, gray.Size), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
unsafe
{
for (var y = 0; y < height; y++)
{
var row = (byte*)bitmapData.Scan0 + y * bitmapData.Stride;
for (var x = 0; x < width; x++)
{
var color = row + x;
float val = 0;
for (int i = -radius, k = 0; i <= radius; i++, k++)
{
var ii = y + i;
if (ii < 0) ii = 0; if (ii >= height) ii = height - 1;
var row2 = (byte*)bitmapData.Scan0 + ii * bitmapData.Stride;
for (int j = -radius; j <= radius; j++)
{
var jj = x + j;
if (jj < 0) jj = 0; if (jj >= width) jj = width - 1;
val += *(row2 + jj) * gaussKernel[k];
}
}
var newColor = 127.5 + 255 * Math.Log(*color / val);
if (newColor > 255)
newColor = 255;
else if (newColor < 0)
newColor = 0;
*color = (byte)newColor;
}
}
}
bmp.UnlockBits(bitmapData);
CvInvoke.cvCopy(gray, ycc, IntPtr.Zero);
CvInvoke.cvSetImageCOI(ycc, 0);
return ycc.Convert<Bgr, byte>();
}
해결책
봐 : http://www.fer.unizg.hr/ipg/resources/color_constancy
이러한 알고리즘은 저자가 재미있는 이름을 주었는데,)
전체 소스 코드가 있습니다 (C ++,하지만 매우 잘 작성됩니다).
다른 팁
네크로포스팅해서 죄송합니다만, 지나가는 사람을 오해할 수 있는 절차의 3단계에 실수가 있는 것 같습니다.
수정 사항을 적용하려면 소스 이미지를 가우스 커널 자체가 아닌 가우스 필터링된 복사본으로 나누기를 원합니다.대략적으로 의사 코드에서는 다음과 같습니다.
I_filtered(x,y) = G(x,y) * I(x,y)
I'(x,y) = log(I(x,y) / I_filtered(x,y))
그런 다음 캐스팅을 적용합니다. I'(x,y)
필수 숫자 유형(uint8
, 원본 게시물에서 참조할 수 있듯이).
해당 주제에 대한 자세한 내용은 다음에서 찾을 수 있습니다. 이 종이:
Ri(x, y) = log(Ii(x, y)) − log(Ii(x, y) ∗ F(x, y))
어디
Ii
i번째 색상 채널의 입력 이미지입니다.Ri
I-th 채널의 Retinex 출력 이미지이며F
정규화된 서라운드 기능입니다..
제휴하지 않습니다 StackOverflow