以(128, 128,128)为中心时该点的对称点,比如rgb(100, 150, 200)对应的反色就是rgb(155, 105, 55)。


       (1)at方法遍历。该方法用起来非常简单、省事,对于待遍历的第i行、第j列像素,只需将(i,j)这个像素点空间位置坐标传给at方法即可。用法如下:



int row = img.rows;
int step = img.step;
for (int i = 0; i < row; i++)
{
    for (int j = 0; j < step; j++)
    {
        img.at<uchar>(i, j) = 255 - img.at<uchar>(i, j);
    }
}
或者:
int row = img.rows;
int col = img.cols;
for (int i = 0; i < row; i++)
{
    for (int j = 0; j < col; j++)
    {
        img.at<Vec3b>(i, j)[0] = 255 - img.at<Vec3b>(i, j)[0];
        img.at<Vec3b>(i, j)[1] = 255 - img.at<Vec3b>(i, j)[1];
        img.at<Vec3b>(i, j)[2] = 255 - img.at<Vec3b>(i, j)[2];
    }
}



       (2)指针方式遍历。由于图像是按照行和列顺序存储的,所以该方法遍历图像时需要先获取图像每一行的首地址,然后从该行首地址向后遍历至行末尾。用法如下:



int row = img.rows;
int step = img.step;
uchar * pImg = img.data;
for (int i = 0; i < row; i++)
{
    for (int j = 0; j < step; j++)
    {
        pImg[j] = 255 - pImg[j];
    }
    pImg += img.step;
}
或者:
int row = img.rows;
int step = img.step;
uchar * pImg = NULL;
for (int i = 0; i < row; i++)
{
    pImg = img.ptr<uchar>(i);
    for (int j = 0; j < step; j++)
    {
        pImg[j] = 255 - pImg[j];
    }
}



       我的测试图像分辨率为:4288 * 2848,对于上述代码,debug模式下,使用at方法用时约9700毫秒,使用指针方式用时约140毫秒;release模式下,at方法用时约63毫秒,指针方式用时约30毫秒。可见使用at方法遍历图像时效率很低,比较耗时,推荐使用指针方式。        



       另外由于像素灰度值范围为0至255,对于某些复杂计算,计算结果难免会超出灰度值范围,这时需要做下数据饱和判断,即结果为负,则取0,结果超出255,则取255。在做饱和判断时可以使用OpenCV提供的saturate_cast函数,对于上述程序,用法为:



pImg[j] = saturate_cast<uchar>(255 - pImg[j]);



不过此时程序用时让人大跌眼镜,release模式下,at方法用时约100毫秒,指针方式用时约62毫秒。即加了饱和判断后,用时增加了近一倍。所以,非必须情况下要慎用这样类似函数。 下面是反色的效果图。


                                        

javacv遍历mat像素的红绿蓝_OpenCV