专栏首页行走的机械人【图像处理100问】图像处理之各种像素操作效果(上)

【图像处理100问】图像处理之各种像素操作效果(上)

学校把很多考试都放在暑假考了,我们专业有6科,分布在一个月内。又要备赛数学建模,快乐暑假已经被榨干了... ...

所以只能利用碎片时间更一篇上次给大家介绍的《视觉图像处理100问》了,因为有原作者写好的代码,所以比较节省时间。关于这个具体资料看上篇文章:

【资源分享1】日本同行整理的视觉处理100问

最近在筹划一篇详解分水岭算法的文章,大家等等吧~

问题一:通道交换

这道题如果用opencv的cvtColor函数写很简单,cvtColor函数可以在绝大部分格式之间转换,具体见下图(截自毛星云《opencv3编程入门》):

我们基于像素操作,自定义一个函数channel_swap()来实现BGR->RGB转换的功能:

// 【1】通道转换
cv::Mat channel_swap(cv::Mat img) {
  // get height and width
  int width = img.cols;
  int height = img.rows;

  // prepare output
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);

  // each y, x
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      // R -> B
      out.at<cv::Vec3b>(y, x)[0] = img.at<cv::Vec3b>(y, x)[2];
      // B -> R
      out.at<cv::Vec3b>(y, x)[2] = img.at<cv::Vec3b>(y, x)[0];
      // G -> G
      out.at<cv::Vec3b>(y, x)[1] = img.at<cv::Vec3b>(y, x)[1];
    }
  }
  return out;
}

程序很简单,就是逐像素主通道进行变换就可以了。

对比opencv的API:cvtColor和自定义函数的运行效果:

问题二:图像转灰度图

RGB转灰度图就是根据上图公式,同样可以根据像素操作来实现:

//【2】BGR -> Gray
cv::Mat BGR2GRAY(cv::Mat img) {
  // get height and width
  int width = img.cols;
  int height = img.rows;

  // prepare output
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);

  // each y, x
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      // BGR -> Gray
      out.at<uchar>(y, x) = 0.2126 * (float)img.at<cv::Vec3b>(y, x)[2] \
        + 0.7152 * (float)img.at<cv::Vec3b>(y, x)[1] \
        + 0.0722 * (float)img.at<cv::Vec3b>(y, x)[0];
    }
  }
  return out;
}

问题三:图像二值化(THresholding)

二值化原理很简单了,利用像素操作加if判断就可以实现:

// Gray -> Binary
cv::Mat Binarize(cv::Mat gray, int th){
  int width = gray.cols;
  int height = gray.rows;

  // prepare output
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);

  // each y, x
  for (int y = 0; y < height; y++){
    for (int x = 0; x < width; x++){
      // Binarize
      if (gray.at<uchar>(y, x) > th){
        out.at<uchar>(y, x) = 255;
      } else {
        out.at<uchar>(y, x) = 0;
      }
    }
  }
  return out;
}

下面对比一下opencv的Threshold()函数和我们自定义函数Binarize()函数:

int main()
{
  Mat srcImage, grayImage,dstImage;

  srcImage = imread("御坂美琴/1.png");//读取图像
  imshow("原图BGR", srcImage);
  cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);//转灰度
  threshold(grayImage, dstImage, 125, 255, THRESH_BINARY);

  imshow("threshold函数阈值化", dstImage);

  Mat out = Binarize(grayImage,125);
  imshow("自定义函数阈值化", out);//自定义函数

  waitKey();
  return 0;
}

问题四:大津二值化算法(Otsu's Method)

// Gray -> Binary 输入图像为灰度图
cv::Mat Binarize_Otsu(cv::Mat gray){
  int width = gray.cols;
  int height = gray.rows;

  // determine threshold
  double w0 = 0, w1 = 0;  //被阈值 t分开的两个类中的像素数占总像素数的比率(满足相加等于1 )
  double m0 = 0, m1 = 0; //是这两个类的像素值的平均值
  double max_sb = 0, sb = 0;
  int th = 0;
  int val;

  // 遍历阈值t的可能值寻求最大值
  for (int t = 0; t < 255; t++){
    w0 = 0;
    w1 = 0;
    m0 = 0;
    m1 = 0;
    for (int y = 0; y < height; y++){  //遍历图像像素点
      for (int x = 0; x < width; x++){
        val = (int)(gray.at<uchar>(y, x)); //获取该点的灰度值

        if (val < t){
          w0++;
          m0 += val;
        } else {
          w1++;
          m1 += val;
        }
      }
    }

    m0 /= w0;//计算大于,小于阈值t的两类像素的像素值的平均值m0 ,m1
    m1 /= w1;
    w0 /= (height * width);//计算大于,小于阈值t的两类像素的个数占总个数的比例w0,w1
    w1 /= (height * width);
    sb = w0 * w1 * pow((m0 - m1), 2); //计算sb的平方

    if(sb > max_sb){ //更新最大值
      max_sb = sb;
      th = t;
    }
  }

  std::cout << "threshold:" << th << std::endl;//打印阈值

  //获取阈值后,对图像进行阈值化
  // prepare output
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC1);

  // each y, x
  for (int y = 0; y < height; y++){
    for (int x = 0; x < width; x++){
      // Binarize
      if (gray.at<uchar>(y, x) > th){
        out.at<uchar>(y, x) = 255;
      } else {
        out.at<uchar>(y, x) = 0;
      }

    }
  }

  return out;
}

处理效果:

本文分享自微信公众号 - Opencv视觉实践(gh_31e12b1be0e0),作者:周旋

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 给彦女王生成一副蒙太奇画像

    大家好呀,前两天烈阳天道1上映了,不知道大家看没看呢,里面还有一小段彦穿越虫洞与猴哥相遇的画面,彦女王啊啊啊~~

    周旋
  • 【资源分享1】日本同行整理的视觉处理100问

    图像处理100问,这个项目切切实实的包含了100个各种直击你薄弱底子的问题,看完可以帮你完善很多的知识漏洞和误区。

    周旋
  • 【opencv】带你再学一遍直方图

    直方图到底可以干什么呢?我觉得最明显的作用就是有利于你对这个图像进行分析了,直方图就像我们常用的统计图,只不过直方图统计的是图片的一些特征,例如像素值(这是最常...

    周旋
  • Expedition (POJ 2431)

    题意:你需要驾驶一辆卡车行驶L单位长度。最开始的时候,卡车上有P单位的油。卡车每开1单位距离需要消耗1单位的汽油。如果在途中车上汽油耗尽,卡车就无法继续前行,因...

    用户7727433
  • LeetCode <dfs>108&109. Array & List to Binary Search Tree

    Given an array where elements are sorted in ascending order, convert it to a hei...

    大学里的混子
  • LeetCode 994. 腐烂的橘子(多源bfs)

           这道题刚开始看错题了,看到了图片就以为是就是从(0, 0)那个点开始,而且只有一个,然后敲完交了就wa了,然后才发现可能刚开始坏橘子有多个,而且还...

    Ch_Zaqdt
  • 【2020HBU天梯赛训练】7-50 部落

    在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不...

    韩旭051
  • Tip | 数据类型占位 & 降采样 & 像素读取 & Bitmap & Color源码

    下面修改通道的时候使用的是位运算, 其实对比Color源码我们知道这跟调用Color的API是一样的:

    凌川江雪
  • 简易却高效的hashmap实现

    我们每天都在使用HashMap,有没有想过,在很多情景下,HashMap做的其实没有特别好,他是一个很通用的k-v数据结构,却不一定在各个小方面都适合.因此我们...

    呼延十
  • Kruscal(最小生成树)算法模版

    1 const int maxn=400;//最大点数 2 const int maxm=10000;//最大边数 3 int n,m;//n表示点数,m...

    Angel_Kitty

扫码关注云+社区

领取腾讯云代金券