第一篇 Frankle-Mccan去雾算法


因为对图像处理感兴趣,就去本部蹭了丁老师的《数字图像处理》课程,感觉比自学效率高多了;

业余时间打算把课上部分代码实现,于是就有了这个博客;这里会不定期更新一些基础算法,大都是老师课上讲的,只注重算法实现,没有进行代码优化;这方面比较厉害的同学可以多多赐教;

PS:编译环境为VS2013+OpenCV3.0alpha;

**第一篇 Frankle-Mccan去雾算法**

PPT上语焉不详;根据PPT写的代码改了好几天效果还是很差,于是参考网上的matlab程序,对原理进行了反推,有了一定的去雾效果;

原理:

一、载入图像,

分为RGB三个通道准备依次处理;

二、参数计算;

求出MaxR、MaxG、MaxB;以及p和S;以Max值生成图像OPR,OPG,OPB;

p=log(min(m,n)-1);

S=2^p;(像素间隔)

三、图像处理:(这里以B通道为例)

3.1 S为指定间隔,求出B通道水平方向上间隔为S的像素差值DP;  

S>0 , 求IP DP=B(i,j+S)-B(i,j); IP=DP+OPB(i,j); 

判断IP是否大于Max,大于Max,则赋予Max if(IP>MaxB) IP=MaxB 

求平均 并赋值给位置j+S的像素 OPB(i,j+S)=OPB(i,j+S)/2+IP/2;  

S<0 求IP DP=B(i,j)-B(i,j+S);IP=DP+OPB(i,j+S); 

判断IP是否大于Max,大于Max,则赋予Max if(IP>MaxB) IP=MaxB 

求平均 并赋值给位置j的像素 OPB(i,j)=OPB(i,j)/2+IP/2;

垂直方向也做类似处理;

3.2 把步骤3.1重复k次

3.3 像素间隔S更新 S/= -2;

我参考的matlab程序在这里

【Frankle-McCann Retinex】matlab代码注释

下面是源代码;欢迎指正

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#define DIEDAI 7

using namespace std;
using namespace cv;
int main()
{
	//读入图像并分离为3个通道;
	Mat src = imread("1.jpg");
	imshow("原图", src);
	Mat Blue, Green, Red;
	vector<Mat> channels;
	split(src, channels);
	Blue = channels.at(0);
	Green = channels.at(1);
	Red = channels.at(2);
	
	//参数计算,三个通道的这几个参数相同
	int rows = Blue.rows;
	int cols = Blue.cols;
	int M = rows < cols ? rows : cols;
	int p = log(M) / log(2) - 1;//阶,这里采用隐式转换
	int S = pow(2, p);              //初始间隔

	//对图层进行处理  求初始OPB OPG OPR
	uchar MaxB = 0, MaxG = 0, MaxR = 0;
	cout << int(MaxB) << endl;
	uchar* dataB = nullptr;
	uchar* dataG = nullptr;
	uchar* dataR = nullptr;
	for (int i = 0; i < rows; i++)
	{
		dataB = Blue.ptr<uchar>(i);
		dataG = Green.ptr<uchar>(i);
		dataR = Red.ptr<uchar>(i);
		for (int j = 0; j < cols; j++)
		{
			if (*dataB > MaxB)
				MaxB = *dataB;
			if (*dataG > MaxG)
				MaxG = *dataG;
			if (*dataR > MaxR)
				MaxR = *dataR;
			dataB++;
			dataG++;
			dataR++;
		}
	}
	dataB = nullptr;
	dataG = nullptr;
	dataR = nullptr;

	Mat OPB(Blue.size(), Blue.depth());
	Mat OPG(Green.size(), Green.depth());
	Mat OPR(Red.size(), Red.depth());
	OPB.setTo(MaxB);
	OPG.setTo(MaxG);
	OPR.setTo(MaxR);

	int DP, IP;
	uchar* Data = nullptr;
	uchar* Data2 = nullptr;
	uchar* OPData = nullptr;
	uchar* OPData2 = nullptr;
	bool fushu = false;    //S是否为负数
		do
		{
			if (S < 0)
			{
				S *= -1;
				fushu = true;     //S为负数,DP=前-后,把差值与OP的J+S行相加得到IP;赋值给第一行
			}
			else
				fushu = false;   //S为正数,DP=后-前,这是把差值与OP的第一行相加得到IP;赋值给+S的位置;

			for (int i = 0; i < DIEDAI; i++)    
			{				
				//B列间隔迭代
				for (int i = 0; i < rows; i++)
				{
					Data = Blue.ptr<uchar>(i);       //获取i行第一个元素的指针
					OPData = OPB.ptr<uchar>(i);
					for (int j = 0; j < cols - S; j++)
					{
						if (fushu) 
						{
							DP = int(Data[j] - Data[j + S]);      //求i行第j+S个元素与第j个元素的差值
							IP = int(OPData[j + S]) + DP;          
							if (IP > MaxB)
								IP = MaxB;
							OPData[j ] = OPData[j] / 2 + IP / 2;
						}
						else
						{
							DP = int(Data[j + S]) - int(Data[j]);
							IP = int(OPData[j]) + DP;
											
							if (IP > MaxB)    
								IP = MaxB;
							OPData[j + S] = OPData[j+S] / 2 + IP / 2;
						}
					}
				}
				//B行间隔迭代
				for (int i = 0; i < rows - S; i++)
				{
					Data = Blue.ptr<uchar>(i);
					Data2 = Blue.ptr<uchar>(i + S);
					OPData = OPB.ptr<uchar>(i);
					OPData2 = OPB.ptr<uchar>(i + S);
					for (int j = 0; j < cols; j++)
					{
						if (fushu)
						{
							DP = int(*Data++ - *Data2++);
							IP = int(*OPData2) + DP;
							if (IP > MaxB)
								IP = MaxB;
							*OPData = *OPData / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
						else
						{
							DP = int(*Data2++ - *Data++);
							IP = int(*OPData) + DP;

							if (IP > MaxB)
								IP = MaxB;
							*OPData2 = *OPData2 / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
					}
				}				
				//G列间隔迭代
				for (int i = 0; i < rows; i++)
				{
					Data = Green.ptr<uchar>(i);
					OPData = OPG.ptr<uchar>(i);
					for (int j = 0; j < cols - S; j++)
					{
						if (fushu)
						{
							DP = int(Data[j] - Data[j + S]);
							IP = int(OPData[j + S]) + DP;
							if (IP > MaxB)
								IP = MaxB;
							OPData[j] = OPData[j] / 2 + IP / 2;
						}
						else
						{
							DP = int(Data[j + S]) - int(Data[j]);
							IP = int(OPData[j]) + DP;

							if (IP > MaxB)
								IP = MaxB;
							OPData[j + S] = OPData[j + S] / 2 + IP / 2;
						}
					}
				}
				//G行间隔迭代
				for (int i = 0; i < rows - S; i++)
				{
					Data = Green.ptr<uchar>(i);
					Data2 = Green.ptr<uchar>(i + S);
					OPData = OPG.ptr<uchar>(i);
					OPData2 = OPG.ptr<uchar>(i + S);
					for (int j = 0; j < cols; j++)
					{
						if (fushu)
						{
							DP = int(*Data++ - *Data2++);
							IP = int(*OPData2) + DP;
							if (IP > MaxB)
								IP = MaxB;
							*OPData = *OPData / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
						else
						{
							DP = int(*Data2++ - *Data++);
							IP = int(*OPData) + DP;

							if (IP > MaxB)
								IP = MaxB;
							*OPData2 = *OPData2 / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
					}
				}
				//R列间隔迭代
				for (int i = 0; i < rows; i++)
				{
					Data = Red.ptr<uchar>(i);
					OPData = OPR.ptr<uchar>(i);
					for (int j = 0; j < cols - S; j++)
					{
						if (fushu)
						{
							DP = int(Data[j] - Data[j + S]);
							IP = int(OPData[j + S]) + DP;
							if (IP > MaxB)
								IP = MaxB;
							OPData[j] = OPData[j] / 2 + IP / 2;
						}
						else
						{
							DP = int(Data[j + S]) - int(Data[j]);
							IP = int(OPData[j]) + DP;

							if (IP > MaxB)
								IP = MaxB;
							OPData[j + S] = OPData[j + S] / 2 + IP / 2;
						}
					}
				}
				//R行间隔迭代
				for (int i = 0; i < rows - S; i++)
				{
					Data = Red.ptr<uchar>(i);
					Data2 = Red.ptr<uchar>(i + S);
					OPData = OPR.ptr<uchar>(i);
					OPData2 = OPR.ptr<uchar>(i + S);
					for (int j = 0; j < cols; j++)
					{
						if (fushu)
						{
							DP = int(*Data++ - *Data2++);
							IP = int(*OPData2) + DP;
							if (IP > MaxB)
								IP = MaxB;
							*OPData = *OPData / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
						else
						{
							DP = int(*Data2++ - *Data++);
							IP = int(*OPData) + DP;
							if (IP > MaxB)
								IP = MaxB;
							*OPData2 = *OPData2 / 2 + IP / 2;
							OPData++;
							OPData2++;
						}
					}
				}
			}
			if (fushu)
				S *= -1;   //恢复S的符号
			S /= -2;
			cout << S << endl;  
		} while (S != 0);  

		Data = nullptr;
		Data2 = nullptr;
		OPData = nullptr;
		OPData2 = nullptr;

		channels.at(0) = OPB;
		channels.at(1) = OPG;
		channels.at(2) = OPR;
		
		Mat dst(src.size(), src.depth());
		merge(channels, dst);   //合并通道

		imshow("结果", dst);

	waitKey(0);
}
原图:
原图在这里

效果图(迭代7次)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值