图片处理 02分段线性变换+均值滤波+中值滤波

对比度拉伸

        为了生成有更高对比度的图片,将输入图像 (Input Image) 中低于L的灰度值,在输出图像 (Output Image) 中全部设为黑(灰度值为0);将输入图像 (Input Image) 中高于H的灰度值,在输出图像 (Output Image) 中全部设为白(灰度值为255);将输入图像 (Input Image) 中L到H之间的灰度值,进行线性缩放 (Linearly Scale);

        而分段对比度拉伸这一操作的具体形式实际上和上面的操作类似,我们从曲线图就可以很直观的了解:

        可以采用如下分段函数:
                                           0<=x<90:f(x)=0.25*x

                                          90<=x<160:f(x)=1.25*x - 0.75

                                          60<=x<250:f(X)=0.25*x + 40

代码如下:

//对比度拉伸
void CBmp::contrastStretching(unsigned char* img_data,
	int bmpWidth, int bmpHeight, int lineByte)
{
	// 定义分段线性函数的参数
	const double a1 = 0.25;
	const double b1 = 0.0;
	const double a2 = 1.25;
	const double b2 = -75.0;
	const double a3 = 0.25;
	const double b3 = 4.0;

	for (int i = 0; i < bmpHeight; i++) {
		for (int k = 0; k < bmpWidth; k++) {
			unsigned char pixelValue = img_data[3 * k];

			// 分段线性函数
			if (pixelValue >= 0 && pixelValue < 90) {
				pixelValue = static_cast<unsigned char>(a1 * pixelValue+b1);
			}
			else if (pixelValue >= 90 && pixelValue < 160) {
				pixelValue = static_cast<unsigned char>(a2 * pixelValue+b2);
			}
			else if (pixelValue >= 160 && pixelValue < 250) {
				pixelValue = static_cast<unsigned char>(a3 * pixelValue+b3);
			}

			img_data[3 * k] = pixelValue;
			img_data[3 * k + 1] = pixelValue;
			img_data[3 * k + 2] = pixelValue;
		}
		img_data += lineByte;
	}
}

均值滤波

        原理:均值滤波是典型的 线性滤波算法,是指用当前像素点周围nxn个像素值的均值来代替当前像素值。使用该方法遍历处理图像内的每一个像素点,可完成整幅图像的均值滤波。

        举个例子:
        

计算方法如下:
像素点新值=
[(197+25+106+156+159)
(149+40+107+5+71)+
(163+198+226+223+156) +
(222+37+68+193+157)+
(42+72+250+41+75)]/25 = 126

代码:

// 均值滤波
void CBmp::meanFilter(unsigned char* img_data, int bmpWidth, int bmpHeight, int lineByte, int filterSize)
{
	int halfFilter = filterSize / 2;   //滤波器一般为正方形,/2就为滤波器的半径
	 
	for (int i = halfFilter; i < bmpHeight - halfFilter; i++) {  //遍历图像每一个像素,在这里避免了边界像素值
		for (int k = halfFilter; k < bmpWidth - halfFilter; k++) {
			double sumR = 0.0, sumG = 0.0, sumB = 0.0;

			// 计算均值
			for (int m = -halfFilter; m <= halfFilter; m++) {   //遍历滤波器每一个像素
				for (int n = -halfFilter; n <= halfFilter; n++) {
					sumB += img_data[3 * (i + m) * bmpWidth + 3 * (k + n) + 0];  // 蓝色通道 3 * (i + m) * bmpWidth为行,3 * (k + n) + 0为列
					sumG += img_data[3 * (i + m) * bmpWidth + 3 * (k + n) + 1];  // 绿色通道
					sumR += img_data[3 * (i + m) * bmpWidth + 3 * (k + n) + 2];  // 红色通道
				}
			}

			// 计算均值并更新像素值
			double pixelValueR = sumR / (filterSize * filterSize);  //filterSize * filterSize为滤波器边长*编程,结果是滤波器像素个数总和
			double pixelValueG = sumG / (filterSize * filterSize);
			double pixelValueB = sumB / (filterSize * filterSize);

			img_data[3 * (i * bmpWidth + k) + 0] = static_cast<unsigned char>(pixelValueB);//将double型转换为unsigned char型
			img_data[3 * (i * bmpWidth + k) + 1] = static_cast<unsigned char>(pixelValueG);
			img_data[3 * (i * bmpWidth + k) + 2] = static_cast<unsigned char>(pixelValueR);
		}
	}

实现效果:

中值滤波

        原理:以某像素的领域图像区域中的像素值的排序为基础,将像素领域内灰度的中值代替该像素的值,使用该方法遍历处理图像内的每一个像素点,可完成整幅图像的均值滤波。

        中值滤波对处理椒盐噪声非常有效。

代码:

//中值滤波
void CBmp::medianFilter(unsigned char* img_data,
    int bmpWidth, int bmpHeight, int lineByte)
{
    // 图像数据副本,确保在计算当前像素的中值时,不会受到已经计算过的像素值的影响
    unsigned char* img_copy = new unsigned char[bmpWidth * bmpHeight * 3];
    memcpy(img_copy, img_data, bmpWidth * bmpHeight * 3);

    for (int i = 3; i < bmpHeight - 3; i++) {
        for (int k = 3; k < bmpWidth - 3; k++) {
            // 7x7邻域内的像素值数组
            unsigned char valuesR[49], valuesG[49], valuesB[49];

            // 获取7x7邻域内的像素值
            for (int m = -3, idx = 0; m <= 3; m++) {
                for (int n = -3; n <= 3; n++, idx++) {
                    valuesR[idx] = img_copy[3 * ((i + m) * bmpWidth + (k + n))];
                    valuesG[idx] = img_copy[3 * ((i + m) * bmpWidth + (k + n)) + 1];
                    valuesB[idx] = img_copy[3 * ((i + m) * bmpWidth + (k + n)) + 2];
                }
            }

            //中值查找
            int middleIndex = 24; // (7 * 7) / 2 = 24
            img_data[3 * (i * bmpWidth + k)] = findMedian(valuesR, 49, middleIndex);
            img_data[3 * (i * bmpWidth + k) + 1] = findMedian(valuesG, 49, middleIndex);
            img_data[3 * (i * bmpWidth + k) + 2] = findMedian(valuesB, 49, middleIndex);
        }
    }

    delete[] img_copy;
}

// 中值查找函数
unsigned char CBmp::findMedian(unsigned char* arr, int size, int middleIndex)
{
    // 使用选择排序找到中值
    for (int i = 0; i < size - 1; i++) {
        for (int j = i + 1; j < size; j++) {
            if (arr[j] < arr[i]) {
                // 交换 arr[i] 和 arr[j]
                unsigned char temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr[middleIndex];
}

实现效果:

参考博文:
Computer Vision笔记01:图像处理_丢弃的原因 对比度阈值-CSDN博客
均值滤波(Mean filtering)-CSDN博客

posted @ 2023-12-05 14:55  Flying3080  Views(53)  Comments(0Edit  收藏  举报  来源