[Журнал] проверить насекомых, чтобы быстро определить, является ли значение только черно-белого изображения серой шкалы (т.е., будь то бинарное изображение) права и неправильно во время переменной BOOL.

  Binary обработка изображений в изображении мы часто встречаются, иногда мы проводим алгоритм предварительной обработки необходимо, чтобы определить, являются ли данные изображения в бинарное изображение в соответствии со спросом, и на этот раз мы можем написать простой функционировать, чтобы быть судьей, к примеру, я написал очень простой код выглядит следующим образом:

BOOL IM_IsBinaryImage_C (беззнаковое символ * Src, Int Ширины, Int Высоты, Int Stride) 
{ 
    Int Channel = Stride / Ширина;
    если (Src == NULL)                             вернуть  ложь ;
    если ((ширина <= 0 ) || (высота <= 0 ))             возвращает  ложь ;
    если (Channel =! 1 )                             вернуться  ложным ;
    для ( Int Y = 0; Y <Высота; Y ++ )                                         
    { 
        беззнаковое символ * LinePS = Src + Y * Страйд;
        для ( междунар X = 0 , X <ширина * Channel; X ++ ) 
        { 
            если (! (LinePS [X] = 255 ) && (LinePS [X] =! 0 ))     вернуться  ложным ;
            // если (((LinePS [X] == 255) || (LinePS [X] == 0)) == ложь) возвращают ложь; 
        } 
    } 
    Вернуться  верно ; 
}

  Т.е., если есть пиксель 255, если нет, то не равен 0, то пара не бинарное изображение на фиг, могут быть возвращены немедленно, без необходимости последующего определения.  

  Когда диаграмма не бинарное изображение, как правило, в скором времени мы сможем вернуть результаты, то наихудший сценарий является то, что он случается бинарное изображение, так и мы закончили обход всех пикселей. Мы тестировали на бинарном изображении (4000 * 4000) 16Мб, требуемое время испытаний 15мс, чтобы свести к минимуму времени, следующее может быть использована для оптимизации инструкции SIMD определения:

BOOL IM_IsBinaryImage_SSE_Bug (беззнаковое символ * Src, Int Ширины, Int Высоты, Int Stride) 
{ 
    Int Channel = Stride / Ширина;
    если (Src == NULL)                             вернуть  ложь ;
    если ((ширина <= 0 ) || (высота <= 0 ))             возвращает  ложь ;
    если (Channel =! 1 )                             вернуться  ложным ;
    INT BlockSize = 16 , блок = (ширина * канал) /Размер блока; 

    для ( Int Y = 0 , Y <высота, Y ++)                                         //     速度提升约16倍
    { 
        беззнаковое полукокса * LinePS = Src + Y * Stride;
        для ( Int Х = 0 , Х <Блок * BlockSize; Х + = BlockSize) 
        { 
            __m128i SrcV = _mm_loadu_si128 ((__ m128i *) (LinePS + Х)); 
            __m128i MaskW = _mm_cmpeq_epi8 (SrcV, _mm_set1_epi8 ( 255 ));        
            __m128i MaskB = _mm_cmpeq_epi8 (SrcV, _mm_setzero_si128 ()); 
            __m128i маска =_mm_or_si128 (MaskW, MaskB);
            если (! _mm_movemask_epi8 (Mask) = 65535 )     возвращают  ложь ;            //     если (((LinePS [X] == 255) || (LinePS [X] == 0)) == ложь) возвращают ложь; 
        }
         Для ( INT X = Блок * BlockSize, X <* Ширина канала, X ++ ) 
        { 
            если (! (LinePS [X] = 255 ) && (LinePS [X] =! 0 ))     вернуться  ложным ; 
        } 
    } 
    Вернуться  верно ; 
}

  由于SIMD指令里没有_mm_cmpneq_epi8函数,我们该用代码1片段里被注释掉的那种逻辑来判断一个像素是否是黑色和白色,这里当然也有一些技巧,比如_mm_movemask_epi8指令的运用。我们判断这个像素是否等于255和0,当然,一个像素不可能同时满足这两个条件,不满足的Mask返回0,满足则Mask返回255,所以如果他是黑色和白色,你们这两个Mask进行或操作肯定就为255,否则或操作后就为0,SIMD中这样的比较可以一次性进行16个像素,如果这16个像素都符合条件,那么或操作后的mask都为255,这样通过使用_mm_movemask_epi8来判断这个mask就完成了16个像素的判断。

  很显然,这个过程的效率要高很多,测试16MB的真二值图,也就1ms就完成了判断。

  好,我用上面的那个代码写成DLL,供C#调用,相关的函数声明如下:

[DllImport("IsBinaryImage.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true)]
 private static extern bool IM_IsBinaryImage_C(byte* Src, int Width, int Height, int Stride);
[DllImport("IsBinaryImage.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern bool IM_IsBinaryImage_SSE_Bug(byte* Src, int Width, int Height, int Stride);

  可出来的结果令我非常诧异,我测试了下面这2幅图:

           

            测试图1                               测视图2 (页面压缩了)

  这两幅图都不是二值图,他们在某些边缘位置都有抗锯齿操作。但是那个IM_IsBinaryImage_C检测图1不是二值图像,检测图2 是二值图像,而IM_IsBinaryImage_SSE_Bug则检测图1是二值图像,图2不是二值图像。开始我以为是我的SSE代码写错了,我就又换了一种写法,如下所示:

bool IM_IsBinaryImage_SSE(unsigned char *Src, int Width, int Height, int Stride)
{
    int Channel = Stride / Width;
    if (Src == NULL)                            return false;
    if ((Width <= 0) || (Height <= 0))            return false;
    if (Channel != 1)                            return false;
    int BlockSize = 16, Block = (Width * Channel) / BlockSize;
    bool Flag = true;
    for (int Y = 0; Y < Height; Y++)                                        //    速度提升约16倍
    {
        unsigned char *LinePS = Src + Y * Stride;
        if (Flag == false)    break;
        for (int X = 0; X < Block * BlockSize; X += BlockSize)
        {
            __m128i SrcV = _mm_loadu_si128((__m128i *)(LinePS + X));
            __m128i MaskW = _mm_cmpeq_epi8(SrcV, _mm_set1_epi8(255));        //    _mm_cmpeq_epi8是自带的,如果使用_mm_cmpneq_epu8则慢了一些。
            __m128i MaskB = _mm_cmpeq_epi8(SrcV, _mm_setzero_si128());
            __m128i Mask = _mm_or_si128(MaskW, MaskB);
            if (_mm_movemask_epi8(Mask) != 65535)
            {
                Flag = false;                            //    if ((LinePS[X] == 255) || (LinePS[X] == 0)) = false, return  false
                break;
            }
        }
        for (int X = Block * BlockSize; X < Width * Channel; X++)
        {
            if ((LinePS[X] != 255) && (LinePS[X] != 0))
            {
                Flag = false;
                break;
            }
        }
    }
    return Flag;
}

  这个时候测绘对所有的图像结果都正确了。

  但是,我觉得代码片段2应该是不会有任何错误的啊。为什么会出现这种现象呢。

  后面从网上查了下,C++的bool变量就只有true和false, 是字节变量,这个可以用printf("%d", sizeof(false));来验证,会打印1。而在其他语言中,似乎是int类型。但是我在C#中用 MessageBox.Show(sizeof(bool).ToString());  似乎也是弹出1。

  但是,当我们把这些函数的返回值都改为int后,在C#中调用就正常了,比如:

int IM_IsBinaryImage_C(unsigned char *Src, int Width, int Height, int Stride)

  也就是说上述的IM_IsBinaryImage_SSE_Bug函数体并无Bug。这到底是怎么回事,还请万能的网络高手有空予以解疑。

  附上测试工程和代码:https://files.cnblogs.com/files/Imageshop/ISBinaryImage.rar

рекомендация

отwww.cnblogs.com/Imageshop/p/11110198.html