问题描述
我正在根据颜色跟踪对象,我正在使用EmguCV库将我的彩色图像阈值化为二进制黑白图像。阈值本身非常快,在320x240图像上50ms。我正在使用RG Chromaticity颜色空间,因此有必要进行一些计算。
I'm working on tracking objects based on color and I was using EmguCV library to threshold my color image to binary black and white image. Thresholding itself was quite fast, 50ms on 320x240 image. I'm using RG Chromaticity color space, so there are some necessarily calculations.
现在我正在尝试使用指针加速它,但结果非常类似于我用emguCV做了什么(每张图片大约50ms)。
Now I'm trying to speed it up using pointers, but the result is very similar with what I did with emguCV (around 50ms per image).
我想问一下,如果有专家可以帮助我,我做错了什么。这是我的颜色阈值实现的简短代码片段。它基于这一个。
I want to ask, if there is some expert who can help me, what I am doing wrong. Here is my short code snippet of my color thresholding implementation. It's based on this one http://www.bobpowell.net/onebit.htm.
public static Bitmap ThresholdRGChroma(Bitmap original, double angleMin,
double angleMax, double satMin, double satMax)
{
Bitmap bimg = new Bitmap(original.Width, original.Height, PixelFormat.Format1bppIndexed);
BitmapData imgData = original.LockBits(new Rectangle(0, 0, original.Width, original.Height), ImageLockMode.ReadOnly, original.PixelFormat);
BitmapData bimgData = bimg.LockBits(new Rectangle(0, 0, bimg.Width, bimg.Height), ImageLockMode.ReadWrite, bimg.PixelFormat);
int pixelSize = 3;
double r, g, angle, sat;
unsafe
{
byte* R, G, B;
byte* row;
int RGBSum;
for (int y = original.Height - 1; y >= 0; y--)
{
row = (byte*)imgData.Scan0 + (y * imgData.Stride);
for (int x = original.Width - 1; x >= 0; x--)
{
// get rgb values
B = &row[x * pixelSize];
G = &row[x * pixelSize + 1];
R = &row[x * pixelSize + 2];
RGBSum = *R + *G + *B;
if (RGBSum == 0)
{
SetIndexedPixel(x, y, bimgData, false);
continue;
}
//calculate r ang g for rg chroma color space
r = (double)*R / RGBSum;
g = (double)*G / RGBSum;
//and angle and saturation
angle = GetAngleRad(r, g) * (180.0 / Math.PI);
sat = Math.Sqrt(Math.Pow(g, 2) + Math.Pow(r, 2));
//conditions to set pixel black or white
if ((angle >= angleMin && angle <= angleMax) && (sat >= satMin && sat <= satMax))
SetIndexedPixel(x, y, bimgData, true);
else
SetIndexedPixel(x, y, bimgData, false);
}
}
}
bimg.UnlockBits(bimgData);
original.UnlockBits(imgData);
return bimg;
}
private unsafe static void SetIndexedPixel(int x, int y, BitmapData bmd, bool pixel)
{
int index = y * bmd.Stride + (x >> 3);
byte* p = (byte*)bmd.Scan0.ToPointer();
byte mask = (byte)(0x80 >> (x & 0x7));
if (pixel)
p[index] |= mask;
else
p[index] &= (byte)(mask ^ 0xff);
}
private static double GetAngleRad(double x, double y)
{
if (x - _rgChromaOriginX == 0)
return 0.0;
double angle = Math.Atan((y - _rgChromaOriginY) / (x - _rgChromaOriginX)); // 10ms
if (x < _rgChromaOriginX && y > _rgChromaOriginY)
angle = angle + Math.PI;
else if (x < _rgChromaOriginX && y < _rgChromaOriginY)
angle = angle + Math.PI;
else if (x > _rgChromaOriginX && y < _rgChromaOriginY)
angle = angle + 2 * Math.PI;
return angle;
}
推荐答案
你做得很多对每个像素进行不必要的数学计算,仅计算精确值以检查它们是否在某些限制范围内。您可以通过预先计算对限制的一些调整来简化比较。
You're doing a lot of unnecessary math for each pixel, calculating exact values only to check to see if they're inside some limits. You can simplify the comparisons by precomputing some adjustments to the limits.
最简单的替换是饱和度。你正在做一个平方根,你可以通过平方限制来避免。
The easiest substitution is for the saturation. You're doing a square root which you can avoid by squaring the limits instead.
double satMin2 = satMin*satMin;
double satMax2 = satMax*satMax;
// ...
sat2 = g*g + r*r;
//conditions to set pixel black or white
if ((angle >= angleMin && angle <= angleMax) && (sat2 >= satMin2 && sat <= satMax2))
角度可以使用类似的技巧。而不是使用Math.Atan计算角度,而不是在r和g范围内找出这些限制等于什么。
A similar trick can be used with the angle. Rather than calculating the angle with Math.Atan, figure out what those limits equate to in your r and g ranges.
这篇关于如何在C#中加快我的颜色阈值处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!