知识点

像素值统计

- 最小(min)

- 最大(max)

- 均值(mean)

- 标准方差(standard deviation)

相关API

  • 最大最小值minMaxLoc
    minMaxLoc() 函数要求输入图像必须是 CV_8UC1 类型的,否则会报错。

  • 计算均值与标准方差meanStdDev
    meanStdDev(Mat src, MatOfDouble mean, MatOfDouble stddev)
    - src 表示输入 Mat 图像

  • mean 表示计算出各个通道的均值,数组长度与通道数目一致

  • stddev 表示计算出各个通道的标准方差,数组长度与通道数目一致

方差的概念与计算公式,例如 两人的5次测验成绩如下:
X: 50,100,100,60,50,平均值E(X)=72;
Y: 73, 70, 75, 72,70 平均值E(Y)=72。
平均成绩相同,但X 不稳定,对平均值的偏离大。

方差描述随机变量对于数学期望的偏离程度。
单个偏离是消除符号影响方差即偏离平方的均值,记为E(X):直接计算公式分离散型和连续型。推导另一种计算公式得到:“方差等于各个数据与其算术平均数的离差平方和的平均数”。其中,分别为离散型和连续型计算公式 [1] 。 称为标准差或均方差,方差描述波动程度。[

](https://blog.csdn.net/Apple_Coco/article/details/93529575)
image.png

C++代码

  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. using namespace std;
  4. using namespace cv;
  5. void day10() {
  6. // 读取一张灰度图像
  7. Mat src_gray = imread("E:\\_Image\\OpenCVTest\\girl.jpg", IMREAD_GRAYSCALE);
  8. if (src_gray.empty()) {
  9. cout << "could not load image.." << endl;
  10. return;
  11. }
  12. imshow("src_gray", src_gray);
  13. if (src_gray.type() == CV_8UC1) {
  14. double minVal = 0, maxVal = 0;
  15. Point minLoc, maxLoc;
  16. minMaxLoc(src_gray, &minVal, &maxVal, &minLoc, &maxLoc, Mat());
  17. printf("min: %.2f, max: %.2f\n", minVal, maxVal);
  18. printf("min loc: (%d, %d)\n", minLoc.x, minLoc.y);
  19. printf("max loc: (%d, %d)\n", maxLoc.x, maxLoc.y);
  20. }
  21. else {
  22. cout << "not gray image.." << endl;
  23. }
  24. // 读取一张三通道彩色图像,获得它的均值和方差
  25. Mat src_color = imread("E:\\_Image\\OpenCVTest\\girl.jpg");
  26. if (src_color.empty()) {
  27. cout << "could not load image.." << endl;
  28. return;
  29. }
  30. imshow("src_color", src_color);
  31. Mat mean, stddev;
  32. meanStdDev(src_color, mean, stddev);
  33. printf("blue channel -> mean: %.2f, stddev: %2f\n", mean.at<double>(0, 0), stddev.at<double>(0, 0));
  34. printf("green channel -> mean: %.2f, stddev: %2f\n", mean.at<double>(1, 0), stddev.at<double>(1, 0));
  35. printf("red channel -> mean: %.2f, stddev: %2f\n", mean.at<double>(2, 0), stddev.at<double>(2, 0));
  36. // 根据图像的均值将彩色图像转换为二值图像
  37. for (int row = 0; row < src_color.rows; row++) {
  38. for (int col = 0; col < src_color.cols; col++) {
  39. Vec3b bgr = src_color.at<Vec3b>(row, col);
  40. bgr[0] = bgr[0] < mean.at<double>(0, 0) ? 0 : 255;
  41. bgr[1] = bgr[1] < mean.at<double>(1, 0) ? 0 : 255;
  42. bgr[2] = bgr[2] < mean.at<double>(2, 0) ? 0 : 255;
  43. src_color.at<Vec3b>(row, col) = bgr;
  44. }
  45. }
  46. imshow("binary", src_color);
  47. waitKey(0);
  48. }

Python代码

  1. import cv2 as cv
  2. import numpy as np
  3. # 查看版本
  4. print(cv.__version__)
  5. # 读取和显示图像
  6. src = cv.imread("E:/_Image/OpenCVTest/girl.jpg", cv.IMREAD_GRAYSCALE)
  7. cv.imshow("src", src)
  8. # 获取灰度图的极值及位置
  9. mmin, mmax, minLoc, maxLoc = cv.minMaxLoc(src)
  10. print("min: %.2f, max: %.2f" % (mmin, mmax))
  11. print("minLoc: ", minLoc)
  12. print("maxLoc: ", maxLoc)
  13. # 获取灰度图的均值和方差
  14. means, stddev = cv.meanStdDev(src)
  15. print("means: %.2f, stddev: %.2f" % (means, stddev))
  16. src[np.where(src < means)] = 0
  17. src[np.where(src > means)] = 255
  18. cv.imshow("binary", src)
  19. ## 彩色图像二值化
  20. src = cv.imread("E:/_Image/OpenCVTest/girl.jpg")
  21. cv.imshow("color", src)
  22. h, w, ch = src.shape
  23. means, stddev = cv.meanStdDev(src)
  24. print("blue channel -> means: %.2f, stddev: %.2f" % (means[0], stddev[0]))
  25. print("green channel -> means: %.2f, stddev: %.2f" % (means[1], stddev[1]))
  26. print("red channel -> means: %.2f, stddev: %.2f" % (means[2], stddev[2]))
  27. print("h, w, ch", h, w, ch)
  28. for row in range(h):
  29. for col in range(w):
  30. b, g, r = src[row, col]
  31. b = 0 if b < means[0] else 255
  32. g = 0 if g < means[1] else 255
  33. r = 0 if r < means[2] else 255
  34. src[row, col] = [b, g, r]
  35. cv.imshow("color_binary", src)
  36. # 等待键盘输入,释放内存
  37. cv.waitKey()
  38. cv.destroyAllWindows()

Javascript代码

  1. <template>
  2. <div>
  3. <p>图像像素值统计</p>
  4. <p id="status">OpenCV.js is loading...</p>
  5. <div class="inputoutput">
  6. <img id="imageSrc" src="imgs/girl.jpg" />
  7. </div>
  8. <div class="inputoutput">
  9. <canvas id="canvasOutput"></canvas>
  10. <div class="caption">canvasOutput</div>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. export default {
  16. name: "day10",
  17. mounted() {
  18. this.init();
  19. },
  20. destoryed() {},
  21. data() {
  22. return {
  23. mats: [],
  24. };
  25. },
  26. methods: {
  27. init() {
  28. setTimeout(() => {
  29. if (window.cv) {
  30. this.onOpenCvReady(window.cv);
  31. } else {
  32. this.init();
  33. }
  34. }, 500);
  35. },
  36. onOpenCvReady(cv) {
  37. document.getElementById("status").innerHTML = "OpenCV.js is ready.";
  38. // 官方文档链接:
  39. // 读取图像
  40. let src = this.createMat(cv, 1, { name: "imageSrc" });
  41. // 转化到 gray 色彩空间
  42. let gray = this.createMat(cv, 2);
  43. cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
  44. // 计算灰度图的极值和位置
  45. // 和 C++,Python 程序运行的结果不一致,感到很奇怪
  46. if (gray.type() === cv.CV_8UC1) {
  47. let ret = cv.minMaxLoc(gray);
  48. console.log(ret);
  49. }
  50. // 计算彩色图的均值和方差
  51. let bgr = this.createMat(cv, 2);
  52. cv.cvtColor(src, bgr, cv.COLOR_RGBA2BGR);
  53. let means = this.createMat(cv, 2);
  54. let stddev = this.createMat(cv, 2);
  55. cv.meanStdDev(bgr, means, stddev);
  56. // this.showImgInfo(means)
  57. // this.showImgInfo(stddev)
  58. // 和 C++,Python 程序运行的结果不一致,感到很奇怪
  59. console.log(`blue channel -> mean: ${means.ucharAt(0, 0)}, stddev: ${stddev.ucharAt(0, 0)}`);
  60. console.log(`green channel -> mean: ${means.ucharAt(1, 0)}, stddev: ${stddev.ucharAt(1, 0)}`);
  61. console.log(`red channel -> mean: ${means.ucharAt(2, 0)}, stddev: ${stddev.ucharAt(2, 0)}`);
  62. // 显示图像
  63. cv.imshow("canvasOutput", gray);
  64. // 销毁所有 mat
  65. this.destoryAllMats();
  66. },
  67. createMat(cv, type, ops) {
  68. switch (type) {
  69. case 1:
  70. if (ops && ops.name) {
  71. let mat = cv.imread(ops.name);
  72. this.mats.push(mat);
  73. return mat;
  74. }
  75. break;
  76. case 2: {
  77. let mat = new cv.Mat();
  78. this.mats.push(mat);
  79. return mat;
  80. }
  81. case 3:
  82. if (ops && ops.rows && ops.cols && ops.type && ops.initValue) {
  83. let mat = new cv.Mat(ops.rows, ops.cols, ops.type, ops.initValue);
  84. this.mats.push(mat);
  85. return mat;
  86. }
  87. break;
  88. default:
  89. break;
  90. }
  91. },
  92. showImgInfo(src) {
  93. console.log("img size :", src.size());
  94. console.log("img type :", src.type());
  95. console.log("img cols :", src.cols);
  96. console.log("img rows :", src.rows);
  97. console.log("img depth:", src.depth());
  98. console.log("img channels:", src.channels());
  99. },
  100. destoryAllMats() {
  101. let i = 0;
  102. this.mats.forEach((item) => {
  103. item.delete();
  104. i++;
  105. });
  106. console.log("销毁图象数:", i);
  107. },
  108. },
  109. };
  110. </script>
  111. <style lang="scss" scoped>
  112. </style>

image.png
image.png
image.png