ImageProcessing100Wen (Opencv C++) Q1-8

准备工作:

首先,配置安装opencv可以戳这里:VS2017配置opencv教程(超详细!!!)

追求可视化的话可以下载一个插件 Image Watch(下载戳这里!) 选择合适的版本进行下载,双击即可完成安装。调试时如果没有显示Image Watch窗口,点击菜单栏 --> 视图 --> 其他窗口 --> image watch,调出该插件。

其次,开头废话多唠一点,因为 100 个有点多,想摆放的整齐一点,所以这些问题我都会放在自己的命名空间 mytinycv 下,引用的其他文件都在头文件中注明,指定的命名空间在源文件中注明,对函数的测试放在类 ImageProcessTest 中用 void 函数封装一下,在 main 直接调用即可,这里我就只贴函数 + 调用 + 显示的结果了。

项目:

项目地址ImageProcessing100Wen极客教程地址

收集了为图像处理初学者设计的 100 个问题以及对应的理论知识。和蝾螈一起学习基本的图像处理知识,理解图像处理算法吧!

解答这里提出的问题请不要调用OpenCV的API,自己动手实践。相信对你掌握opencv有比较好的帮助。

问题 1-8:
1通道交换
2灰度化(Grayscale)
3二值化(Thresholding)
4大津二值化算法(Otsu's Method)
5HSV 变换
6减色处理
7平均池化(Average Pooling)
8最大池化(Max Pooling)

Q1: 通道交换

问题说明:

RGB代表红绿蓝。大多数情况下,RGB颜色存储在结构或无符号整数中。BGR除了区域顺序颠倒其他是相同的。

早期开发者使用BGR作为颜色的空间是因为:那个时候的BGR格式在相机制造厂商和软件提供商之间比较受欢迎。感兴趣可以戳:为什么使用BGR格式?

在opencv中,我们来看下如何读取图像,然后将 RGB 通道替换成 BGR 通道这样的Opencv通道交换。

下面的代码用于提取图像的红色通道。注意,cv2.imread() 的系数是按 BGR 顺序排列的!其中的变量 red 表示的是仅有原图像红通道的 imori.jpg。

在这里插入图片描述

C++实现:
	Mat SwapChannels(Mat srcImg){
		int width = srcImg.cols;
		int height = srcImg.rows;

		Mat dstImg = Mat::zeros(height, width, CV_8UC3);
		//交换通道顺序
		for (int y = 0; y < height; ++y) {
			for (int x = 0; x < width; ++x) {
				dstImg.at<Vec3b>(y, x)[0] = srcImg.at<Vec3b>(y, x)[2];
				dstImg.at<Vec3b>(y, x)[2] = srcImg.at<Vec3b>(y, x)[0];
				dstImg.at<Vec3b>(y, x)[1] = srcImg.at<Vec3b>(y, x)[1];
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat bgr = SwapChannels(image);
	namedWindow("sample", 0);
	imshow("sample", bgr);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
图片替换文本

Q2: 灰度化(Grayscale)

问题说明:

灰度是一种图像亮度的表示方法,将彩色图像转化成为灰度图像的过程称为图像的灰度化处理。

在RGB模型中,如果 R = G = B R=G=B R=G=B 时,则彩色表示一种灰度颜色,其中 R = G = B R=G=B R=G=B 的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为 0-255。

图像灰度化的算法主要有以下 3 种:

  1. 最大值法
    将彩色图像中的三分量亮度的最大值作为灰度图的灰度值。

    R = G = B = m a x ( R , G , B ) R=G=B=max(R,G,B) R=G=B=max(R,G,B)

  2. 平均值法
    将彩色图像中的三分量亮度求平均得到一个灰度值。

    R = G = B = ( R + G + B ) / 3 R=G=B=(R+G+B) / 3 R=G=B=(R+G+B)/3

  3. 加权平均法
    根据重要性及其它指标,将三个分量以不同的权值进行加权平均。由于人眼对绿色的敏感最高,对蓝色敏感最低,因此 w w wG> w w wR> w w wB 时能得到较合理的灰度图像),按下式对RGB三分量进行加权平均。

    R = G = B = ( w R R + w G G + w B B ) / 3 R=G=B=(w_RR+w_GG+w_BB) / 3 R=G=B=(wRR+wGG+wBB)/3

    OpenCV开放库所采用的灰度权值:
    G r a y = 0.072169 B + 0.715160 G + 0.212671 R Gray= 0.072169B+0.715160G+0.212671R Gray=0.072169B+0.715160G+0.212671R

    从人体生理学角度所提出的一种权值:
    G r a y = 0.11 B + 0.59 G + 0.3 R Gray= 0.11B+0.59G+0.3R Gray=0.11B+0.59G+0.3R

这里只用 G r a y = 0.072169 B + 0.715160 G + 0.212671 R Gray= 0.072169B+0.715160G+0.212671R Gray=0.072169B+0.715160G+0.212671R 来实现。

C++实现:
	Mat BGR2GRAY(Mat srcImg) {
		int width = srcImg.cols;
		int height = srcImg.rows;

		Mat dstImg = Mat::zeros(height, width, CV_8UC1);

		for (int y = 0; y < height; ++y) {
			for (int x = 0; x < width; ++x) {
				dstImg.at<uchar>(y, x) = 0.072169*(float)srcImg.at<Vec3b>(y, x)[0]\
					+ 0.715160*(float)srcImg.at<Vec3b>(y, x)[1]\
					+ 0.212671*(float)srcImg.at<Vec3b>(y, x)[2];
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat gray = BGR2GRAY(image);
	namedWindow("sample", 0);
	imshow("sample", gray);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
图片替换文本

Q3: 二值化(Thresholding)

问题说明:

图像二值化是将 256 个亮度等级的灰度图像通过适当的阈值选取,仍然可以获得反映图像整体和局部特征的方法,它使图像变得简单,减小数据量,也能凸显出感兴趣的目标的轮廓。

所有灰度大于或等于阈值的像素被判定为属于特定物体,其灰度值用 255 表示,否则这些像素点被排除在物体区域以外;灰度值为 0 表示背景或者例外的物体区域。

这里我们将灰度的阈值设置为 128 来进行二值化:

即 y = 0      (if y < 128)
          255  (else)

C++实现:
	Mat Binarize(Mat srcGray, int th) {
		int width = srcGray.cols;
		int height = srcGray.rows;

		Mat dstImg = Mat::zeros(height, width, CV_8UC1);

		for (int y = 0; y < height; ++y) {
			for (int x = 0; x < width; ++x) {
				if (srcGray.at<uchar>(y, x) < th)
					dstImg.at<uchar>(y, x) = 0;
				else
					dstImg.at<uchar>(y, x) = 255;
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat gray = BGR2GRAY(image);
	Mat binary = Binarize(gray, 128);
	namedWindow("sample", 0);
	imshow("sample", binary);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
图片替换文本

Q4: 大津二值化算法(Otsu’s Method)

问题说明:

大津二值化算法也被称作最大类间方差法,是一种可以自动确定二值化中阈值的算法,从类内方差和类间方差的比值计算得来:

  • 小于阈值 t t t 的类记作 0,大于阈值 t t t 的类记作 1;
  • w 0 w_0 w0 w 1 w_1 w1 是被阈值 t t t 分开的两个类中的像素数占总像素数的比率(满足 w 0 + w 1 = 1 w_0 + w_1 =1 w0+w1=1);
  • S 0 2 S_0^2 S02 S 1 2 S_1^2 S12 是这两个类中像素值的方差;
  • M 0 M_0 M0 M 1 M_1 M1 是这两个类的像素值的平均值;

也就是说:

类内方差: S w 2 S_w^2 Sw2 = w 0 w_0 w0 * S 0 2 S_0^2 S02 + w 1 w_1 w1 * S 1 2 S_1^2 S12

类间方差: S b 2 S_b^2 Sb2 = w 0 w_0 w0 * ( M 0 M_0 M0 - M t M_t Mt)2 + w 1 w_1 w1 * ( M 1 M_1 M1 - M t M_t Mt)2 = w 0 w_0 w0 * w 1 w_1 w1 * ( M 0 M_0 M0 - M 1 M_1 M1)2

图像所有像素的方差: S t 2 S_t^2 St2 = S w 2 S_w^2 Sw2 + S b 2 S_b^2 Sb2 = (const)

根据以上的式子,分离度: X X X = S b 2 S w 2 S_b^2 \over S_w^2 Sw2Sb2 = S b 2 S t 2 − S w 2 S_b^2 \over {S_t^2 - S_w^2} St2Sw2Sb2,函数图像大致如下 (只取不小于 0 的部分):

图片名称



a r g m a x t X argmax_tX argmaxtX = a r g m a x t S b 2 argmax_tS_b^2 argmaxtSb2,如果 S b 2 S_b^2 Sb2 最大,就可以得到最好的二值化阈值 t。

C++实现:
	Mat OtsuBinarize(Mat srcGray) {
		int width = srcGray.cols;
		int height = srcGray.rows;

		double w0 = 0, w1 = 0;
		double m0 = 0, m1 = 0;
		double maxVariance = 0, variance = 0;
		int th = 0;
		//遍历枚举求类间方差最大时的阈值th
		for (int tmpth = 0; tmpth < 255; tmpth++) {
			w0 = w1 = 0;
			m0 = m1 = 0;
			for (int y = 0; y < height; ++y) {
				for (int x = 0; x < width; ++x) {
					if (srcGray.at<uchar>(y, x) < tmpth) {
						++w0;
						m0 += srcGray.at<uchar>(y, x);
					}
					else {
						++w1;
						m1 += srcGray.at<uchar>(y, x);
					}
				}
			}
			//计算每类的像素平均值和每类占比
			m0 = (w0 == 0) ? 0: m0 / w0;
			m1 = (w1 == 0) ? 0 : m1 / w1;
			w0 = w0 / (width*height);
			w1 = w1 / (width*height);
			variance = w0 * w1*pow(m0 - m1, 2);
			if (variance > maxVariance) {
				maxVariance = variance;
				th = tmpth;
			}
		}
		//再利用th进行二值化操作
		Mat dstImg = Binarize(srcGray, th);
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat gray = BGR2GRAY(image);
	Mat ostu = OtsuBinarize(gray);
	namedWindow("sample", 0);
	imshow("sample", ostu);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
图片名称

Q5: HSV 变换

问题说明:

HSV 变换就是 HSV 色彩和 RGB 色彩之间互相转换的过程。

HSV 是使用色相(Hue)、饱和度(Saturation)、明度(Value)来表示色彩的一种方式。

  • 色相:将颜色使用 0 到 360 度表示,就是平常所说的颜色名称,如红色、蓝色。色相与数值按下表对应:
绿品红
060120180240300360
  • 饱和度:是指色彩的纯度,饱和度越低则颜色越黯淡( 0 ≤ S < 1 0\leq S < 1 0S<1);
  • 明度:即颜色的明暗程度。数值越高越接近白色,数值越低越接近黑色 ( 0 ≤ V < 1 0 \leq V < 1 0V<1);

从 RGB 色彩表示转换到 HSV 色彩表示通过以下方式计算:

R,G,B的值在 [0, 1] 之间:

M a x = m a x ( R , G , B ) Max = max(R,G,B) Max=max(R,G,B)
M i n = m i n ( R , G , B ) Min = min(R,G,B) Min=min(R,G,B)

H =   0 ,                                                                      ( i f     M i n = M a x ) H =\ 0, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (if \ \ \ Min=Max) H= 0,                                                                    (if   Min=Max)
           60 ∗ ( G − R ) / ( M a x − M i n ) + 60 ,              ( i f     M i n = B ) \ \ \ \ \ \ \ \ \ \ 60 * (G-R) / (Max-Min) + 60,\ \ \ \ \ \ \ \ \ \ \ \ (if \ \ \ Min=B)           60(GR)/(MaxMin)+60,            (if   Min=B)
           60 ∗ ( B − G ) / ( M a x − M i n ) + 180 ,            ( i f     M i n = R ) \ \ \ \ \ \ \ \ \ \ 60 * (B-G) / (Max-Min)+180, \ \ \ \ \ \ \ \ \ \ (if \ \ \ Min=R)           60(BG)/(MaxMin)+180,          (if   Min=R)
           60 ∗ ( R − B ) / ( M a x − M i n ) + 300 ,            ( i f     M i n = G ) \ \ \ \ \ \ \ \ \ \ 60 * (R-B) / (Max-Min)+300 ,\ \ \ \ \ \ \ \ \ \ (if \ \ \ Min=G)           60(RB)/(MaxMin)+300,          (if   Min=G)


V = M a x V = Max V=Max
S = M a x − M i n S = Max - Min S=MaxMin

HSV -> RGB 转换由以下公式定义:

C = S C = S C=S
H ′ = H / 60 H' = H / 60 H=H/60
X = C ∗ ( 1 − ∣ H ′ m o d   2 − 1 ∣ ) X = C * (1 - |H' mod\ 2 - 1|) X=C(1Hmod 21)

( R , G , B ) = ( V − C ) ( 1 , 1 , 1 ) + ( 0 , 0 , 0 )           ( i f    H    i s    u n d e f i n e d ) (R,G,B) = (V - C) (1,1,1) + (0, 0, 0)\ \ \ \ \ \ \ \ \ (if \ \ H\ \ is \ \ undefined) (R,G,B)=(VC)(1,1,1)+(0,0,0)         (if  H  is  undefined)
                                                     ( C , X , 0 )         ( i f    0 ≤ H ′ < 1 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (C, X, 0)\ \ \ \ \ \ \ (if\ \ 0 \leq H' < 1)                                                     (C,X,0)       (if  0H<1)
                                                     ( X , C , 0 )         ( i f    1 ≤ H ′ < 2 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (X, C, 0) \ \ \ \ \ \ \ (if \ \ 1 \leq H' < 2)                                                     (X,C,0)       (if  1H<2)
                                                     ( 0 , C , X )         ( i f    2 ≤ H ′ < 3 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (0, C, X) \ \ \ \ \ \ \ (if \ \ 2 \leq H' < 3)                                                     (0,C,X)       (if  2H<3)
                                                     ( 0 , X , C )         ( i f    3 ≤ H ′ < 4 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (0, X, C)\ \ \ \ \ \ \ (if \ \ 3 \leq H' < 4)                                                     (0,X,C)       (if  3H<4)
                                                     ( X , 0 , C )         ( i f    4 ≤ H ′ < 5 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (X, 0, C) \ \ \ \ \ \ \ (if \ \ 4\leq H' < 5)                                                     (X,0,C)       (if  4H<5)
                                                     ( C , 0 , X )         ( i f    5 ≤ H ′ < 6 ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (C, 0, X)\ \ \ \ \ \ \ (if \ \ 5 \leq H' < 6)                                                     (C,0,X)       (if  5H<6)

请将色相反转(色相值加180),然后再用 RGB 色彩空间表示图片。

C++实现:
	//BGR->HSV
	Mat BGR2HSV(Mat srcImg) {
		int width = srcImg.cols;
		int height = srcImg.rows;

		float b, g, r;
		float h, s, v;
		float _max, _min;

		Mat dstImg = Mat::zeros(height, width, CV_32FC3);

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				b = (float)srcImg.at<Vec3b>(y, x)[0] / 255;
				g = (float)srcImg.at<Vec3b>(y, x)[1] / 255;
				r = (float)srcImg.at<Vec3b>(y, x)[2] / 255;

				_max = fmax(b, fmax(g, r));
				_min = fmin(b, fmin(g, r));

				//计算色相Hue 将颜色使用0-360度表示
				if (_max == _min)
					h = 0;
				else if (_min == b)
					h = 60 * (g - r) / (_max - _min) + 60;
				else if (_min == r)
					h = 60 * (b - g) / (_max - _min) + 180;
				else if (_min == g)
					h = 60 * (r - b) / (_max - _min) + 300;

				//计算饱和度Saturation
				s = _max - _min;

				//计算明度Value
				v = _max;

				dstImg.at<Vec3f>(y, x)[0] = h;
				dstImg.at<Vec3f>(y, x)[1] = s;
				dstImg.at<Vec3f>(y, x)[2] = v;
			}
		}
		return dstImg;
	}

	//色相反转
	Mat InverseHue(Mat srcHsv) {
		int width = srcHsv.cols;
		int height = srcHsv.rows;

		Mat dstImg = srcHsv.clone();
		//对每个点色相值+180
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				dstImg.at<Vec3f>(y, x)[0] = fmod(srcHsv.at<Vec3f>(y, x)[0] + 180, 360);
			}
		}
		return dstImg;
	}

	//HSV->BGR
	Mat HSV2BGR(Mat srcHsv) {
		int width = srcHsv.cols;
		int height = srcHsv.rows;

		float h, s, v;
		float c, _h, _x;
		float r, g, b;

		Mat dstImg = Mat::zeros(height, width, CV_8UC3);

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				h = srcHsv.at<Vec3f>(y, x)[0];
				s = srcHsv.at<Vec3f>(y, x)[1];
				v = srcHsv.at<Vec3f>(y, x)[2];

				c = s;
				_h = h / 60;
				_x = c * (1 - abs(fmod(_h, 2) - 1));

				r = g = b = v - c;
				//v-c 即_max-(_max-_min)>=0
				if (_h >= 0 && _h < 1) {
					r += c;
					g += _x;
				}
				else if (_h < 2) {
					r += _x;
					g += c;
				}
				else if (_h < 3) {
					g += c;
					b += _x;
				}
				else if (_h < 4) {
					g += _x;
					b += c;
				}
				else if (_h < 5) {
					r += _x;
					b += c;
				}
				else if (_h < 6) {
					r += c;
					b += _x;
				}

				dstImg.at<Vec3b>(y, x)[0] = (uchar)(b * 255);
				dstImg.at<Vec3b>(y, x)[1] = (uchar)(g * 255);
				dstImg.at<Vec3b>(y, x)[2] = (uchar)(r * 255);
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat hsv = BGR2HSV(image);
	namedWindow("sample1", 0);
	imshow("sample1", hsv);

	hsv = InverseHue(hsv);
	namedWindow("sample2", 0);
	imshow("sample2", hsv);

	Mat bgr = HSV2BGR(hsv);
	namedWindow("sample3", 0);
	imshow("sample3", bgr);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

1   2   3

Q6: 减色处理

问题说明:

我们将图像的值由 2563 压缩至 43,即 RGB 的值只取 32,96,160,224,这被称作色彩量化。色彩的值按照下面的方式定义:

v a l = 32         ( 0 ≤ v a l < 64 ) val = 32 \ \ \ \ \ \ \ ( 0 \leq val < 64) val=32       (0val<64)
            96         ( 64 ≤ v a l < 128 ) \ \ \ \ \ \ \ \ \ \ \ 96 \ \ \ \ \ \ \ ( 64 \leq val < 128)            96       (64val<128)
            160       ( 128 ≤ v a l < 192 ) \ \ \ \ \ \ \ \ \ \ \ 160 \ \ \ \ \ (128 \leq val < 192)            160     (128val<192)
            224       ( 192 ≤ v a l < 256 ) \ \ \ \ \ \ \ \ \ \ \ 224 \ \ \ \ \ (192 \leq val < 256)            224     (192val<256)

C++实现:
	Mat DecreaseColor(Mat srcImg) {
		int width = srcImg.cols;
		int height = srcImg.rows;

		int channel = srcImg.channels();

		Mat dstImg = Mat::zeros(height, width, CV_8UC3);

		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				for (int c = 0; c < channel; c++) {
					dstImg.at<Vec3b>(y, x)[c] = (uchar)(floor((double)srcImg.at<Vec3b>(y, x)[c] / 64) * 64 + 32);
				}
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat img = DecreaseColor(image);
	namedWindow("sample", 0);
	imshow("sample", img);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
sample3

Q7: 平均池化(Average Pooling)

问题说明:

将图片按照固定大小网格分割,网格内的像素值取网格内所有像素的平均值。我们将这种把图片使用均等大小网格分割,并求网格内代表值的操作称为池化(Pooling)。池化操作是卷积神经网络(Convolutional Neural Network)中重要的图像处理方式。平均池化按照下式定义:

v = 1 ∣ R ∣ ∗ ∑ i R v i v = \frac{1}{|R|} * \sum_i^R v_i v=R1iRvi

请把大小为 128×128 的 imori.jpg 使用 8×8 的网格做平均池化。

C++实现:
	Mat AveragePooling(Mat srcImg) {
		int width = srcImg.cols;
		int height = srcImg.rows;
		int channel = srcImg.channels();

		Mat dstImg = Mat::zeros(height, width, CV_8UC3);
		//网格尺寸8*8
		int kernelSize = 8;
		double val = 0;

		//边界处理上,最好保证图片能被网格均分,这里简单的舍弃了不能被均分的部分
		for (int y = 0; y < height - height % kernelSize; y += kernelSize) {
			for (int x = 0; x < width - width % kernelSize; x += kernelSize) {
				for (int c = 0; c < channel; c++) {
					//分别对网格内值求和求均值存入输出图中
					val = 0;
					for (int dy = 0; dy < kernelSize; dy++) {
						for (int dx = 0; dx < kernelSize; dx++) {
							val += (double)srcImg.at<Vec3b>(y + dy, x + dx)[c];
						}
					}
					val /= (kernelSize * kernelSize);
					for (int dy = 0; dy < kernelSize; dy++) {
						for (int dx = 0; dx < kernelSize; dx++) {
							dstImg.at<Vec3b>(y + dy, x + dx)[c] = (uchar)val;
						}
					}
				}
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat img = AveragePooling(image);
	namedWindow("sample", 0);
	imshow("sample", img);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
sample3

Q8: 最大池化(Max Pooling)

问题说明:

网格内的值不取平均值,而是取网格内的最大值进行池化操作,叫做最大池化。

请把大小为 128×128 的 imori.jpg 使用 8×8 的网格做最大池化。

C++实现:
	Mat MaximumPooling(Mat srcImg) {
		int width = srcImg.cols;
		int height = srcImg.rows;
		int channel = srcImg.channels();

		Mat dstImg = Mat::zeros(height, width, CV_8UC3);
		//网格尺寸8*8
		int kernelSize = 8;
		double val = 0;

		//边界处理上,最好保证图片能被网格均分,这里简单的舍弃了不能被均分的部分
		for (int y = 0; y < height - height % kernelSize; y += kernelSize) {
			for (int x = 0; x < width - width % kernelSize; x += kernelSize) {
				for (int c = 0; c < channel; c++) {
					//求取网格内最大值
					val = 0;
					for (int dy = 0; dy < kernelSize; dy++) {
						for (int dx = 0; dx < kernelSize; dx++) {
							val = fmax((double)srcImg.at<Vec3b>(y + dy, x + dx)[c], val);
						}
					}
					for (int dy = 0; dy < kernelSize; dy++) {
						for (int dx = 0; dx < kernelSize; dx++) {
							dstImg.at<Vec3b>(y + dy, x + dx)[c] = (uchar)val;
						}
					}
				}
			}
		}
		return dstImg;
	}
测试及结果:
int main(){
	Mat image = imread("..\\Resource\\imori.jpg");
	Mat img = MaximumPooling(image);
	namedWindow("sample", 0);
	imshow("sample", img);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
sample3
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值