• opencv之图像元素遍历(反色) 笔记


    opencv版本号: opencv3.4.1

    目录

    1. 下标M.at(i, j)

    2. 指针遍历Mat::ptr

    3. 迭代器Matlterator_

     4. isContinuout方法

     5. LUT查表法

    图像处理中需要对图像的像素点进行遍历,遍历图像像素的算法影响运行速度;以图像反色为例,有以下几种算法;

    1. 下标M.at(i, j)

    1. cv::Mat inverseColor1(cv::Mat srcImage)
    2. {
    3. cv::Mat tempImage = srcImage.clone();
    4. int row = tempImage.rows;
    5. int col = tempImage.cols;
    6. for(int i = 0; i < row; i++){
    7. for(int j = 0; j < col; j++){
    8. //对各个通道进行反色处理
    9. tempImage.at(i,j)[0] = 255 - srcImage.at(i,j)[0];
    10. tempImage.at(i,j)[1] = 255 - srcImage.at(i,j)[1];
    11. tempImage.at(i,j)[2] = 255 - srcImage.at(i,j)[2];
    12. }
    13. }
    14. return tempImage;
    15. }

    2. 指针遍历Mat::ptr

    1. cv::Mat inverseColor2(cv::Mat srcImage)
    2. {
    3. cv::Mat tempImage = srcImage.clone();
    4. int row = tempImage.rows;
    5. //将3通道转换为单通道
    6. //std::cout << " row=" << row << " cols=" << tempImage.cols << " channels=" << tempImage.channels() << endl;
    7. int nStep = tempImage.cols * tempImage.channels();
    8. for(int i = 0; i < row; i++){
    9. //取源图像指针
    10. const uchar *pSrcData = srcImage.ptr(i);
    11. uchar *pResultData = tempImage.ptr(i);
    12. for(int j = 0; j < nStep; j++){
    13. pResultData[j] = cv::saturate_cast(255-pSrcData[j]);
    14. }
    15. }
    16. return tempImage;
    17. }

    3. 迭代器Matlterator_

    1. cv::Mat inverseColor3(cv :: Mat srcImage)
    2. {
    3. cv::Mat tempImage = srcImage.clone();
    4. //初始化源图像迭代器
    5. cv::MatConstIterator_ srcIterStart = srcImage.begin();
    6. cv::MatConstIterator_ srcIterEnd = srcImage.end();
    7. //初始化输出图像迭代器
    8. cv::MatIterator_ resIterStart = tempImage.begin();
    9. cv::MatIterator_ resIterEnd = tempImage.end();
    10. while(srcIterStart != srcIterEnd)
    11. {
    12. (*resIterStart)[0] = 255 - (*srcIterStart)[0];
    13. (*resIterStart)[1] = 255 - (*srcIterStart)[1];
    14. (*resIterStart)[2] = 255 - (*srcIterStart)[2];
    15. srcIterStart++;
    16. resIterStart++;
    17. }
    18. return tempImage;
    19. }

     4. isContinuout方法

    图像数据的存储行与行间可能是空白单元,即图像行与行间的存储可能是不连续的,所以在使用上述方法进行图像的遍历时,很大程度上会造成指针的移动浪费;所以用isContunuout函数判断图像元素存储是连续的;

    1. cv::Mat inverseColor4(cv :: Mat srcImage)
    2. {
    3. int row = srcImage.rows;
    4. int col = srcImage.cols;
    5. cv::Mat tempImage = srcImage.clone();
    6. //判断是否有连续图像,即是否有像素填充
    7. if(srcImage.isContinuous() && tempImage.isContinuous()){
    8. row = 1;
    9. col = col * srcImage.rows * srcImage.channels();
    10. }
    11. for(int i = 0 ;i < row; i++){
    12. const uchar *pSrcData = srcImage.ptr(i);
    13. uchar *pResultData = tempImage.ptr(i);
    14. for(int j =0 ; j < col; j++){
    15. *pResultData = 255 - *pSrcData;
    16. pResultData++;
    17. pSrcData++;
    18. }
    19. }
    20. return tempImage;
    21. }

     5. LUT查表法

    为了减少图像映射的时间复杂度,提供了查找表LUT;

    1. cv::Mat inverseColor5(cv :: Mat srcImage)
    2. {
    3. int row = srcImage.rows;
    4. int col = srcImage.cols;
    5. cv::Mat tempImage = srcImage.clone();
    6. //建立LUT反色table
    7. uchar LutTab[256];
    8. for(int i =0 ; i < 256; i++){
    9. LutTab[i] = 255 - i;
    10. }
    11. cv::Mat lookUpTable(1, 256, CV_8U);
    12. uchar *pData = lookUpTable.data;
    13. //建立映射表
    14. for(int i = 0; i < 256; i++){
    15. pData[i] = LutTab[i];
    16. }
    17. //利用索引查找
    18. cv::LUT(srcImage, lookUpTable, tempImage);
    19. return tempImage;
    20. }

    测试代码:

    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(srcImage.empty()){
    5. std::cout << "imread failed" << endl;
    6. return -1;
    7. }
    8. double tTime;
    9. tTime = (double)getTickCount();
    10. //cv::Mat dstImage = inverseColor1(srcImage); //运行时间Max 7.30422
    11. //cv::Mat dstImage = inverseColor2(srcImage); //运行时间Max 1.88004
    12. //cv::Mat dstImage = inverseColor3(srcImage); //运行时间Max 8.38001
    13. //cv::Mat dstImage = inverseColor4(srcImage); //运行时间Max 1.66753
    14. cv::Mat dstImage = inverseColor5(srcImage); //运行时间Max 1.26254
    15. tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
    16. std::cout << tTime << std::endl;
    17. cv::imwrite("./lena_inverse5.jpg", dstImage);
    18. return 0;
    19. }

    getTickCount()和getTickFrequency()函数用来计时测试代码的运行时间;

  • 相关阅读:
    【Web 实战】记一次攻防实战
    聊聊SpringBootTest的webEnvironment
    JVM入个门(1)
    如何快速除掉项目中的console
    Stable Diffusion 最新Ebsynth Utility脚本生成AI动画视频
    一致性hash负载均衡
    mysql和redis库存扣减和优化
    SAP中外协加工收货与反冲消耗数量不一致的产生原因分析和解决案例二
    SpringJdbc之最强版本,附带十个开源案例!!!!
    02 | 如何进行code diff
  • 原文地址:https://blog.csdn.net/qq_39048131/article/details/126348660