影像拉伸优化

Qt、GDAL遥感影像显示

影像拉伸优化

使用GDAL读取影像数据之后,需要进行拉伸显示。比如读取landsat数据时,由于数据类型时ushort,如果直接显示,那么显示的结果就是一片空白。因此我们需要对数据进行拉伸,将ushort拉伸到0-255。因此出现以下三种拉伸方法。

方案1(最慢)

	for(int index = 0; index < pImpObject->bandMap.length(); ++index) {
		int bandMap = pImpObject->bandMap[index] + 1;
		cv::Mat tmp = cv::Mat(buf.y, buf.x, GisEntsHelper::GDALType2GCType(dType, 1));
		GDALRasterBand *pBand = pDataset->GetRasterBand(bandMap);
		CPLErr err = pBand->RasterIO(GF_Read, read.x, read.y, size.x, size.y, tmp.data, tmp.cols, tmp.rows, dType, 0, 0);
		GisEntsHelper::GisLineStretchImage(tmp, pImpObject->histArray[index], sType, GisEntsHelper::GDALTypeMaxValue(dType));
		mats.push_back(tmp.clone());
	}
void GisEntsHelper::GisLineStretchImage(cv::Mat &mat, const HistogramData &histData, OGis::StretchType sType, uint maskValue)
{
	cv::Mat mask1;
	cv::compare(mat, histData._noDataValue, mask1, cv::CMP_EQ);
	mat.setTo(maskValue, mask1);
	if(sType != OGis::kStretch_No) {
		switch(sType) {
			case OGis::kStretch_Line:
			case OGis::kStretch_Line1:
			case OGis::kStretch_Line2:
			case OGis::kStretch_Line5:
				cv::threshold(mat, mat, histData.minmax[sType - 1].x, 0, cv::THRESH_TOZERO);
				cv::threshold(mat, mat, histData.minmax[sType - 1].y, 255, cv::THRESH_TRUNC);
				mat = (mat - histData.minmax[sType - 1].x) * histData.minmax[sType - 1].z;
				mat.convertTo(mat, CV_8U);
				break;
			case OGis::kStretch_Equalize:
				cv::normalize(mat, mat, 255, 0, CV_MINMAX, CV_8U);
				cv::equalizeHist(mat, mat); break;
		}
	}
}

方案2(中等)

for(int index = 0; index < pImpObject->bandMap.length(); ++index) {
	int bandMap = pImpObject->bandMap[index] + 1;
	cv::Mat tmp = cv::Mat(buf.y, buf.x, GisEntsHelper::GDALType2GCType(dType, 1));
	GDALRasterBand *pBand = pDataset->GetRasterBand(bandMap);
	CPLErr err = pBand->RasterIO(GF_Read, read.x, read.y, size.x, size.y, tmp.data, tmp.cols, tmp.rows, dType, 0, 0);
	mats.push_back(tmp.clone());
}
GisEntsHelper::GisLineStretchImage(mats, pImpObject->histArray, sType, 0);
void GisEntsHelper::GisLineStretchImage(std::vector<cv::Mat> &mats, const HistogramDataArray &hists, OGis::StretchType sType, uint trans)
{
	if(sType == OGis::kStretch_No) {
		return;
	}
	std::vector<cv::Mat> temps = mats;
	cv::Mat mask; mats.clear();
	if(temps.size() == 3) {
		mask = ((temps[0] == temps[0]) & (temps[1] == temps[0]) & (temps[2] == temps[0]));
		temps[0].setTo(hists[0]._max, mask); temps[1].setTo(hists[1]._max, mask); temps[2].setTo(hists[2]._max, mask);
	}
	else {
		mask = ~cv::Mat(temps[0] == temps[0]);
		temps[0].setTo(hists[0]._max, mask);
	}
	for(int idx = 0; idx < temps.size(); ++idx) {
		cv::Mat mat = temps[idx]; HistogramData hist = hists[idx];
		cv::Mat result = cv::Mat(temps[0].rows, temps[0].cols, CV_8U);
		if(sType <= OGis::kStretch_Line5) {
			Double3 minmax = hist.minmax[sType - 1];
			for(int row = 0; row < mat.rows; ++row) {
				for(int col = 0; col < mat.cols; ++col) {
					double val = GetMatValue(mat, row, col);
					if(isnan(val)) {
						result.at<byte>(row, col) = 255;
						continue;
					}
					if(val < minmax.x) {
						val = 0;
					}
					else if(val > minmax.y) {
						val = 255;
					}
					else {
						val = (val - minmax.x) * minmax.z;
					}
					result.at<byte>(row, col) = val;
				}
			}
		}
		else if(OGis::kStretch_SquareRoot == sType) {
			if(hist._min < 0) {
				mat -= hist._min;
			}
			mat.convertTo(mat, CV_32F);
			mat = (mat - hist._min) * hist.minmax[sType - 1].x + hist.minmax[sType - 1].y;
			mat.convertTo(result, CV_8U);
		}
		else if(OGis::kStretch_Logaithmic == sType) {
			if(hist._min < 1) {
				mat -= (hist._min - 1);
			}
			mat.convertTo(mat, CV_32F);
			mat = (mat - hist._min) * hist.minmax[sType - 1].x + hist.minmax[sType - 1].y;
			mat.convertTo(result, CV_8U);
		}
		else if(OGis::kStretch_Gaussian == sType) {
		}
		else if(OGis::kStretch_Equalize == sType) {
			cv::normalize(mat, result, 255, 0, CV_MINMAX, CV_8U);
			cv::equalizeHist(result, result);
		}

		mats.push_back(result.clone());
	}
}

方案2的代码量虽然比较多,但是速度比方案1确实快了一点点。

方案3(最快)

for(int index = 0; index < pImpObject->bandMap.length(); ++index) {
	int bandMap = pImpObject->bandMap[index] + 1;
	cv::Mat tmp = cv::Mat(buf.y, buf.x, GisEntsHelper::GDALType2GCType(dType, 1));
	GDALRasterBand *pBand = pDataset->GetRasterBand(bandMap);
	CPLErr err = pBand->RasterIO(GF_Read, read.x, read.y, size.x, size.y, tmp.data, tmp.cols, tmp.rows, dType, 0, 0);
	mats.push_back(tmp.clone());
}
GisEntsHelper::GisLineStretchImageEx(mats, pImpObject->histArray, sType, 0);
void GisEntsHelper::GisLineStretchImageEx(std::vector<cv::Mat> &mats, const HistogramDataArray &hists, OGis::StretchType sType, uint trans)
{
	if(sType == OGis::kStretch_No) {
		return;
	}
	std::vector<cv::Mat> temps;
	cv::Mat mask;

	if(mats.size() == 3) {
		mask = ((mats[0] == hists[0]._noDataValue) & (mats[1] == hists[1]._noDataValue) & (mats[2] == hists[2]._noDataValue));
	}
	else {
		mask = ~cv::Mat(mats[0] == mats[0]);
	}
	for(int idxMat = 0; idxMat < mats.size(); ++idxMat) {
		mats[idxMat].setTo(hists[idxMat]._max, mask);
		HistogramData hist = hists[idxMat]; cv::Mat result;
		mats[idxMat].convertTo(result, CV_8U, 255.0 / (hist._max - hist._min), -255.0 * hist._min / (hist._max - hist._min));
		if(OGis::kStretch_Equalize == sType) {
			cv::equalizeHist(result, mats[idxMat]);
		}
		temps.push_back(result);
	}
	if(OGis::kStretch_Equalize == sType) {
		return;
	}
	mats.clear();
	for(int idxMat = 0; idxMat < temps.size(); ++idxMat) {
		HistogramData hist = hists[idxMat];
		cv::Mat lookTableMat = cv::Mat(1, 256, CV_8U);
		uchar *pData = lookTableMat.data;
		double valMin, valMax, factor;
		Double3 minmax = hist.minmax[sType - 1];
		double dMin = hist._min, dMax = hist._max;
		if(sType <= OGis::kStretch_Line5) {
			valMin = 255.0 * (minmax.x - hist._min) / (hist._max - hist._min);
			valMax = 255.0 * (minmax.y - hist._min) / (hist._max - hist._min);
		}
		else if(sType == OGis::kStretch_SquareRoot) {
			valMin = sqrt(0);
			valMax = sqrt(255);
		}
		else if(sType == OGis::kStretch_Logaithmic) {
			valMin = log(1);
			valMax = log(256);
		}
		factor = 255.0 / (valMax - valMin);
		for(int idx = 0; idx < 256; ++idx) {
			double val = idx;
			if(OGis::kStretch_SquareRoot == sType)  val = sqrt(idx);
			else if(OGis::kStretch_Logaithmic == sType)  val = log(idx + 1);
			if(val < valMin) pData[idx] = 0;
			else if(val > valMax) pData[idx] = 255;
			else pData[idx] = (val - valMin) * factor;
		}
		cv::Mat result = cv::Mat(temps[idxMat].rows, temps[idxMat].cols, CV_8U);
		cv::LUT(temps[idxMat], lookTableMat, result);
		mats.push_back(result.clone());
	}
}

方案3使用OpenCV查找表进行数据的拉伸。

分析原因

方案原因
方案1对mat进行了6次遍历
方案2对mat进行了2次遍历
方案3对mat进行了2次遍历,第二次使用的是cv::LUT,这个效率不是遍历像素可比的
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值