SSE影象演算法優化系列二十三: 基於value-and-criterion structure 系列濾波器(如Kuwahara,MLV,MCV濾波器)的優化。
阿新 • • 發佈:2018-12-15
int IM_KuwaharaFilter(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride, int Radius)
{
int Channel = Stride / Width;
if ((Src == NULL) || (Dest == NULL)) return IM_STATUS_NULLREFRENCE;
if ((Width <= 0) || (Height <= 0)) return IM_STATUS_INVALIDPARAMETER;
if ((Channel != 1) && (Channel != 3)) return IM_STATUS_INVALIDPARAMETER;
int Status = IM_STATUS_OK;
unsigned char *Average = (unsigned char *)malloc(Height * Width * sizeof(unsigned char));
int *Deviation = (int *)malloc(Height * Width * sizeof(int));
int *RowOffset = (int *)malloc((Width + Radius + Radius) * sizeof(int));
int *ColOffset = (int *)malloc((Height + Radius + Radius) * sizeof(int));
unsigned char *Blur = NULL;
if ((Average == NULL) || (Deviation == NULL) || (RowOffset == NULL) || (ColOffset == NULL))
{
Status = IM_STATUS_OUTOFMEMORY;
goto FreeMemory;
}
if (Channel == 1)
{
Status = IM_GetLocalMeanAndDeviationFilter(Src, Average, Deviation, Width, Height, Stride, Radius, false);
if (Status != IM_STATUS_OK) goto FreeMemory;
}
else
{
Blur = (unsigned char *)malloc(Height * Stride * sizeof(unsigned char)); // 彩色需要使用明度通道來計算均方差,不然會出現彩色異常塊
if (Blur == NULL)
{
Status = IM_STATUS_OUTOFMEMORY;
goto FreeMemory;
}
Status = IM_GetLuminance(Src, Average, Width, Height, Stride, false); // 得到明度通道
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_GetLocalMeanAndDeviationFilter(Average, NULL, Deviation, Width, Height, Width, Radius, false); // 無需儲存對應的均值,因為沒用
if (Status != IM_STATUS_OK) goto FreeMemory;
Status = IM_BoxBlur(Src, Blur, Width, Height, Stride, Radius); // 彩色模糊
if (Status != IM_STATUS_OK) goto FreeMemory;
}
for (int Y = 0; Y < Height + Radius + Radius; Y++)
ColOffset[Y] = IM_GetMirrorPos(Height, Y - Radius);
for (int X = 0; X < Width + Radius + Radius; X++)
RowOffset[X] = IM_GetMirrorPos(Width, X - Radius);
for (int Y = 0; Y < Height; Y++)
{
int *LinePST = Deviation + ColOffset[Y] * Width; // 均方差
int *LinePSB = Deviation + ColOffset[Y + Radius + Radius] * Width;
unsigned char *LinePD = Dest + Y * Stride;
if (Channel == 1)
{
unsigned char *LinePT = Average + ColOffset[Y] * Width; // 均值
unsigned char *LinePB = Average + ColOffset[Y + Radius + Radius] * Width;
for (int X = 0; X < Width; X++)
{
int OffsetL = RowOffset[X]; // 求4個點的均方差的最小值
int OffsetR = RowOffset[X + Radius + Radius];
int Min, Mean;
if (LinePST[OffsetL] < LinePST[OffsetR])
{
Min = LinePST[OffsetL];
Mean = LinePT[OffsetL];
}
else
{
Min = LinePST[OffsetR];
Mean = LinePT[OffsetR];
}
if (Min > LinePSB[OffsetL])
{
Min = LinePSB[OffsetL];
Mean = LinePB[OffsetL];
}
if (Min > LinePSB[OffsetR])
{
Min = LinePSB[OffsetR];
Mean = LinePB[OffsetR];
}
LinePD[X] = Mean;
}
}
else
{
unsigned char *LinePT = Blur + ColOffset[Y] * Stride; // 均值
unsigned char *LinePB = Blur + ColOffset[Y + Radius + Radius] * Stride;
for (int X = 0; X < Width; X++)
{
int OffsetL = RowOffset[X]; // 求4個點的均方差的最小值
int OffsetR = RowOffset[X + Radius + Radius];
int Min, MeanB, MeanG, MeanR;
if (LinePST[OffsetL] < LinePST[OffsetR])
{
Min = LinePST[OffsetL];
MeanB = LinePT[OffsetL * 3 + 0];
MeanG = LinePT[OffsetL * 3 + 1];
MeanR = LinePT[OffsetL * 3 + 2];
}
else
{
Min = LinePST[OffsetR];
MeanB = LinePT[OffsetR * 3 + 0];
MeanG = LinePT[OffsetR * 3 + 1];
MeanR = LinePT[OffsetR * 3 + 2];
}
if (Min > LinePSB[OffsetL])
{
Min = LinePSB[OffsetL];
MeanB = LinePB[OffsetL * 3 + 0];
MeanG = LinePB[OffsetL * 3 + 1];
MeanR = LinePB[OffsetL * 3 + 2];
}
if (Min > LinePSB[OffsetR])
{
Min = LinePSB[OffsetR];
MeanB = LinePB[OffsetR * 3 + 0];
MeanG = LinePB[OffsetR * 3 + 1];
MeanR = LinePB[OffsetR * 3 + 2];
}
LinePD[0] = MeanB;
LinePD[1] = MeanG;
LinePD[2] = MeanR;
LinePD += 3;
}
}
}
FreeMemory:
if (Average != NULL) free(Average);
if (Deviation != NULL) free(Deviation);
if (RowOffset != NULL) free(RowOffset);
if (ColOffset != NULL) free(ColOffset);
if (Blur != NULL) free(Blur);
return Status;
}