OpenCV批量处理tiff图片黑边,QT环境(附源码)

这几天基础OpenCV,练习写了一个去黑边程序,新手代码,记录一下。
该方法为扫描线法,遇到非黑边内的(0,0,0)黑色时,用坐标排除(不在边界上跳过)。
PS:这里还提供一种区域增长思路,找图片黑色区域,面积最大的区域为需要去除的黑边。

基本思路

  1. 遍历导入图片,遍历像素,找到黑边所在的矩形框坐标,剪切图片(一分为四)。
  2. 根据矩形坐标,计算新的地理位置信息。
  3. 删除带有黑边的图片和tfw文件信息
  4. 打开和写入保存tif图片和tfw位置信息

找到黑边所在的矩形区域,分割图片。

//传入图片   返回图片分割的图片  得到切点坐标
QVector<Mat> separationTif(Mat &iplImg, Point2d &cutPnt)
{
	QVector<Mat> vecMat;
	int width = iplImg.size().width;
	int height = iplImg.size().height;
	int begin_wid = 0, end_wid = 0, begin_heig = 0, end_heig = 0;     //标记黑边 坐标   
	int i = 0, j = 0;
	int blackNumber = 0;
	for (j = 0; j < height; ++j)
	{
		for (i = 0; i < width; ++i)
		{
			int tmpb, tmpg, tmpr;
			tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0];
			tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1];
			tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2];
			if (tmpb == 0 && tmpg == 0 && tmpr == 0)			//这里RGB数字可以灵活变动
			{
				++blackNumber;
			}
		}
	}

	if (blackNumber == 0)			//不存在黑边
	{
		vecMat << iplImg;
		return vecMat;
	}
	else
	{
		for (j = 0; j < height; ++j)
		{
			bool flag = false;
			for (i = 0; i < width; ++i)
			{
				int tmpb, tmpg, tmpr;
				tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0];
				tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1];
				tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2];
				if (tmpb == 0 && tmpg == 0 && tmpr == 0)
				{
					if (i > 0 && i < width - 1 && j > 0 && j < height - 1)
						;
					else
					{
						flag = true;
						begin_heig = j;
						break;
					}
				}
			}
			if (flag) break;
		}

		for (j = height - 1; j >= begin_heig; --j)
		{
			bool flag = false;			//判断
			for (i = 0; i < width; ++i)
			{
				int tmpb, tmpg, tmpr;
				tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0];
				tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1];
				tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2];
				if (tmpb == 0 && tmpg == 0 && tmpr == 0)
				{
					if (i > 0 && i < width - 1 && j > 0 && j < height - 1)
						;
					else
					{
						flag = true;
						end_heig = j;
						break;
					}
				}
			}
			if (flag) break;
		}
		
		for (i = 0; i < width; ++i)
		{
			bool flag = false;
			for (j = 0; j < height; ++j)
			{
				int tmpb, tmpg, tmpr;
				tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0];
				tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1];
				tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2];
				if (tmpb == 0 && tmpg == 0 && tmpr == 0)
				{
					if (i > 0 && i < width - 1 && j > 0 && j < height - 1)
						;
					else
					{
						flag = true;
						begin_wid = i;
						break;
					}
				}
			}
			if (flag) break;
		}

		for (i = width - 1; i >= begin_wid; --i)
		{
			bool flag = false;
			for (j = 0; j < height; ++j)
			{
				int tmpb, tmpg, tmpr;
				tmpb = cvGet2D(&(IplImage)iplImg, j, i).val[0];
				tmpg = cvGet2D(&(IplImage)iplImg, j, i).val[1];
				tmpr = cvGet2D(&(IplImage)iplImg, j, i).val[2];
				if (tmpb == 0 && tmpg == 0 && tmpr == 0)
				{
					if (i > 0 && i < width - 1 && j > 0 && j < height - 1)
						;
					else
					{
						flag = true;
						end_wid = i;
						break;
					}
				}
			}
			if (flag) break;
		}
		
		if (begin_wid > 0 && begin_wid < (width - 1))
			cutPnt.x = begin_wid;
		else
			cutPnt.x = end_wid;

		if (begin_heig > 0 && begin_heig < (height - 1))
			cutPnt.y = begin_heig;
		else
			cutPnt.y = end_heig;

		if (cutPnt.x != 0 || cutPnt.y != 0)
		{				//裁剪的中心点不在(0,0)时  剪切图像
			cout << "裁剪的中心点为:" << endl;
			qDebug() << cutPnt.x << cutPnt.y;
			Mat img0 = Mat(iplImg, Rect(0, 0, cutPnt.x + 1, cutPnt.y + 1));									//左上
			Mat img1 = Mat(iplImg, Rect(0, cutPnt.y, cutPnt.x + 1, height - cutPnt.y - 1));					//左下
			Mat img2 = Mat(iplImg, Rect(cutPnt.x, 0, width - cutPnt.x - 1, cutPnt.y + 1));					//右上
			Mat img3 = Mat(iplImg, Rect(cutPnt.x, cutPnt.y, width - cutPnt.x - 1, height - cutPnt.y - 1)); 	//右下
			vecMat << img0 << img1 << img2 << img3;
		}
		else
		{
			qDebug() << "Do not have black_border";
			vecMat << iplImg;
		}
		return vecMat;
	}
}

计算图片分割后每张图的tfw位置信息

//传入剪切点的坐标和tfw文件信息   返回tfw
QVector<QList<QString>> getTfw(Point2d &cutPnt, QList<QString> &listString)
{
	double resolutionX = listString.at(0).trimmed().toDouble();		//A  去\n然后转化成数字
	double ranslation = listString.at(1).trimmed().toDouble();		//D
	double rotate = listString.at(2).trimmed().toDouble();			//B
	double resolutionY = listString.at(3).trimmed().toDouble();		//E
	double actualX = listString.at(4).trimmed().toDouble();			//C
	double actualY = listString.at(5).trimmed().toDouble();			//F
	double x = resolutionX * cutPnt.x + rotate * cutPnt.y + actualX;		//x'=Ax+By+C   计算新的位置坐标
	double y = ranslation *cutPnt.x + resolutionY * cutPnt.y + actualY;		//y'=Dx+Ey+F   

	QList<QString> listString0, listString1, listString2, listString3;
	for (int i = 0; i<listString.size(); ++i)
	{
		listString0 << listString.at(i);
		listString1 << listString.at(i);
		listString2 << listString.at(i);
		listString3 << listString.at(i);
	}
	listString1[5] = QString::number(y, 10, 3) + "\n";
	listString2[4] = QString::number(x, 10, 3) + "\n";
	listString3[4] = QString::number(x, 10, 3) + "\n";
	listString3[5] = QString::number(y, 10, 3) + "\n";
	QVector<QList<QString>> vecTfw;
	if (cutPnt.x == 0 && cutPnt.y == 0)
		return vecTfw << listString0;
	else
	{
		vecTfw << listString0 << listString1 << listString2 << listString3;
		return vecTfw;
	}
}

删除带有黑边的图片

//去除不符合标准的图片和tfw  (对应的图片有黑边)
void dele(QVector<Mat> &vecTif, QVector<QList<QString>> &vecTfw)
{
	if (vecTif.size() == 1)
		return ;
	else
	{
		for (int i = 0; i < vecTif.size(); ++i)
		{
			int blackNumber = 0;
			for (int j = 0; j < vecTif.at(i).size().height; j++)
			{
				for (int k = 0; k < vecTif.at(i).size().width; k++)
				{
					int tmpb, tmpg, tmpr;
					tmpb = cvGet2D(&(IplImage)vecTif.at(i), j, k).val[0];
					tmpg = cvGet2D(&(IplImage)vecTif.at(i), j, k).val[1];
					tmpr = cvGet2D(&(IplImage)vecTif.at(i), j, k).val[2];
					if (tmpb == 0 && tmpg == 0 && tmpr == 0)
					{
						++blackNumber;
					}
				}
			}
			if (blackNumber > 100)				//不局限与100 可以适当调整
			{
				vecTif.remove(i, 1);		  //从vector中移除从 i开始的count个元素
				vecTfw.remove(i, 1);		//只有一个图片被删除
				
			}
		}
	}
}

写入保存tif图片和tfw位置信息

//传入打开和保存的文件夹  写入文件
void removeBlack(QString &openFolderPath, QString &saveFolderPath)
{	
	//打开文件夹文件夹下tif文件路径
	QDir dirImg(openFolderPath);
	// 设置过滤器
	QStringList filtersTif;
	filtersTif << "*.tif";
	dirImg.setNameFilters(filtersTif);
	QStringList  m_imgList = dirImg.entryList();

	QDir dirText(openFolderPath);

	QStringList filtersTfw;
	filtersTfw << "*.tfw";
	dirText.setNameFilters(filtersTfw);
	QStringList  m_textList = dirText.entryList();

	for (int i = 0; i < m_imgList.size(); ++i)
	{
		QString imgPath = openFolderPath + "//" + m_imgList.at(i);			//图片路径
		QString tfwPath = openFolderPath + "//" + m_textList.at(i);			//文件路径
		qDebug() << "OpenPath:" << endl << imgPath;
		string sourcePath = string((const char *)imgPath.toLocal8Bit());			//Qstring 转string 
		Mat iplImg = imread(sourcePath, CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);

		QList<QString> listString;   //一个文件的所有字符
		QFile file(tfwPath);
		if (file.open(QIODevice::ReadOnly | QIODevice::Text))
		{
			while (!file.atEnd())
			{
				QByteArray line = file.readLine();
				QString str(line);
				//qDebug() << str;
				listString << str;
			}
			file.close();
		}
		
		QString saveTifName = m_imgList.at(i).section('.', 0, 0);			//从打开文件中   提取   保存文件的部分路径
		Point2d cutPnt;
		QVector<Mat> vecMat = separationTif(iplImg, cutPnt);
		QVector<QList<QString>> vecTfw = getTfw(cutPnt, listString);
		dele(vecMat, vecTfw);
		qDebug() << vecMat.size() << vecTfw.size();

		if (vecMat.size() != 0)
		{
			for (int i = 0; i < vecMat.size(); ++i)
			{
				QString temp;
				temp.setNum(i);
				QString qsaveTifPath = saveFolderPath + "\\" + saveTifName + "__" + temp + ".tif";
				QString qsavetfwPath = saveFolderPath + "\\" + saveTifName + "__" + temp + ".tfw";
				string savePath = string((const char *)qsaveTifPath.toLocal8Bit());		//QString 转string
				if (vecMat.at(i).size().width != 0 && vecMat.at(i).size().height != 0)
				{
					imwrite(savePath, vecMat.at(i));
					qDebug() << "SavePath:" << endl << qsaveTifPath;
					QString str,allStr;
					foreach(str, vecTfw.at(i))
					{
						allStr = allStr + str;
					}
					QFile file(qsavetfwPath);
					file.open(QIODevice::WriteOnly | QIODevice::Text);
					file.write(allStr.toUtf8());
					file.close();
				}
			}
		}
	}
	qDebug() << "OK";
}

至此所有处理函数全部完成,在主程序中只需要调用removeBlack()函数,然后 传入路径就可以。

.
.
.
源码:https://download.csdn.net/download/qq_42610313/11540662
出现问题:
1、处理图片速度较慢,测试了60+图片,发现有一张图片暴露问题。
2、当遍历有少量黑色像素时,存在Bug。
2、打开处理后的所有图片,发现有少量漏洞,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值