Вопрос

Я работаю над объектами отслеживания на основе цвета, и я использовал библиотеку Emgucv, чтобы порог мое цветное изображение на двоичное черное и белом изображении.Пороговое значение сам было довольно быстро, 50 мс на образе 320x240.Я использую цветное пространство цветности RG, поэтому есть некоторые обязательные расчеты.

Теперь я пытаюсь ускорить его, используя указатели, но результат очень похож на то, что я сделал с Emgucv (около 50 мс на изображение).

Я хочу спросить, если есть какой-то эксперт, который может мне помочь, что я делаю не так.Вот мой короткий кодовый фрагмент моей пороговой реализации цветов.Он основан на этом http://www.bobpowell.net/onebowlet.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;
}
.
Это было полезно?

Решение

Вы делаете много ненужной математики для каждого пикселя, вычисляя точные значения только для проверки, если они внутри каких-либо ограничений.Вы можете упростить сравнения путем предварительно перемещения некоторых настроек до предела.

Самая легкая замена предназначена для насыщения.Вы делаете квадратный корень, который вы можете избежать, вместо этого корректируя пределы.

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.

Другие советы

Я не уверен, если будет быстрее.Но Здесь я написал совет, какРабота с растровыми изображениями очень быстро.

Для полноты, вот модифицирована версия порогового изображения в RG цветное пространство цветного пространства более чем в 2 раза быстрее, чем версия в моем вопросе.

public static Bitmap ThresholdRGChroma(Bitmap original, Rectangle roi, double angle,
            double width, 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, sat, m; double satMin2 = satMin * satMin; double satMax2 = satMax * satMax; double cr = Math.Sin((2 * Math.PI * angle) / 360.0); double cg = Math.Cos((2 * Math.PI * angle) / 360.0); // Instead of (Math.Cos(2 * width / 180.0) + 1) / 2.0 I'm using pre-calculated <1; 0> values. double w2 = -width; 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--) { 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; } r = (double)*R / RGBSum - _rgChromaOriginX; g = (double)*G / RGBSum - _rgChromaOriginY; m = cr * r + cg * g; sat = r * r + g * g; if (m > 0 && m * m > w2 * w2 * sat && sat >= satMin2 && sat <= satMax2) SetIndexedPixel(x, y, bimgData, true); else SetIndexedPixel(x, y, bimgData, false); } } } bimg.UnlockBits(bimgData); original.UnlockBits(imgData); return bimg; }

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top