0
点赞
收藏
分享

微信扫一扫

图论 - 最短路(Dijkstra、Bellman-Ford、SPFA、Floyd)

迎月兮 03-03 13:00 阅读 2

根据https://github.com/Shiyuuuu/image_metrics/blob/main/niqe.py代码改编,结果精度会不同,如果可以调整的很好的话,欢迎告知

测试代码:

①多线程调用模式

//多线程调用
void test_speed()
{
	string Path = R"(E:\2024Work\2\image_result\pathologic\0clear\0_0.jpg)";
	Mat input_mat = imread(Path);
	string file_path = R"(E:\2024Work\2\ILNIQE\test\Param.txt)";
	ScanQualityEvaluator sqe;
	sqe.start_calc(6, file_path);  //启动6个线程,来计算

	int loop_counts = 200;
	auto st = CMyLog::getCurrentTime();
	for (int i = 0; i < loop_counts; i++)
	{
		// 图片添加到队列
		sqe.push_back(input_mat.data, input_mat.rows, input_mat.cols,1);
	}
	sqe.stop_calc();  //等待停止
	double total_times = CMyLog::getSpanTimes(st, CMyLog::getCurrentTime());
	cout << total_times / loop_counts << endl;
}

②单测模式


void test_1()
{
	string Path = R"(E:\2024Work\2\image_result\pathologic\1blur\0_0.jpg)";
	Mat rgbImg = imread(Path);
    //模型文件
	string file_path = R"(E:\2024Work\2\ILNIQE\test\Param.txt)";

	ScanQualityEvaluator::_CalculateILNIQE_Ready(file_path);

	ScanQualityEvaluator::_CalculateILNIQE(cut_img);
}

代码:

#pragma once
#include <opencv2/opencv.hpp>
#include "../BaseCode/BnvQueue.hpp"

//计算扫描质量的接口
class ScanQualityEvaluator
{
public:
	//Path 是均值和方差文件
	static double _CalculateILNIQE(const cv::Mat img, int block_size_h = 96, int block_size_w = 96);
	static int _CalculateILNIQE_Ready(std::string path);

	
	//type=0  raw 1 rgb
	int push_back(unsigned char* data, int rows, int cols, int type = 0);
	//启动多少个线程来处理
	int start_calc(int thread_nums,std::string path);
	double stop_calc(); //要等待线程结束  返回计算的值

private:
	static std::tuple<float, float, float> _estimate_aggd_param(const cv::Mat& block);
	static std::vector<float> _compute_feature(const cv::Mat& block);

private:
	void _Start();
	double _Stop();
	int setStatus(int status);
	int config(int thread_nums, std::string path);
private:
	int m_status;  //0 是表示启动  1表示停止
	std::mutex m_img_q_vals_lock;
	std::vector<double> m_img_q_vals;
	BnvQueue<cv::Mat> m_rgb_img_queue;
	std::vector<std::thread> m_threads;

	//NIQE的均值,方差矩阵
	static cv::Mat mu_pris_param;
	static cv::Mat cov_pris_param;
	static cv::Mat gaussian_window;
	static std::vector<float> gam;
	static std::vector<float> r_gam;
};
#include "ScanQualityEvaluator.hpp"
#include <vector>
#include <numeric>
#include "MyLog.h"
#include <fstream>
#include <Tool.h>
using namespace cv;
using namespace std;

cv::Mat ScanQualityEvaluator::mu_pris_param;
cv::Mat ScanQualityEvaluator::cov_pris_param;
cv::Mat ScanQualityEvaluator::gaussian_window;
std::vector<float> ScanQualityEvaluator::gam;
std::vector<float> ScanQualityEvaluator::r_gam;

std::tuple<float, float, float> ScanQualityEvaluator::_estimate_aggd_param(const Mat& block) {
	// 将图像块展平
	Mat block_flattened = block.clone().reshape(1, 1); // 展平为行向量

	//计算标准差
	float negative_sum = 0.0, positive_sum = 0.0;
	int negative_counts = 0, positive_counts = 0;


	float* p = block_flattened.ptr<float>(0);
	float val;
	for (int i = 0; i < block_flattened.cols; ++i)
	{
		val = *p++;
		if (val < 0)
		{
			negative_sum += val *val;
			++negative_counts;
		}
		else
		{
			positive_sum += val * val;
			++positive_counts;
		}
	}


	float left_std = sqrt(negative_sum / negative_counts);
	float right_std = sqrt(positive_sum/ positive_counts);

	float gammahat = left_std / right_std;
	float rhat = std::pow(mean(abs(block_flattened))[0], 2) / mean(block_flattened.mul(block_flattened))[0];
	float rhatnorm = (rhat * (std::pow(gammahat, 3) + 1) * (gammahat + 1)) / std::pow((std::pow(gammahat, 2) + 1), 2);
	size_t array_position = std::distance(r_gam.begin(), std::min_element(r_gam.begin(), r_gam.end(), [&](float a, float b) { return std::abs(a - rhatnorm) < std::abs(b - rhatnorm); }));

	float alpha = gam[array_position];
	float beta_l = left_std * std::sqrt(std::tgamma(1 / alpha) / std::tgamma(3 / alpha));
	float beta_r = right_std * std::sqrt(std::tgamma(1 / alpha) / std::tgamma(3 / alpha));

	return std::make_tuple(alpha, beta_l, beta_r);
}


//50ms
std::vector<float> ScanQualityEvaluator::_compute_feature(const Mat& block) {
	std::vector<float> feat;
	// 计算 alpha、beta_l 和 beta_r 参数
	float alpha, beta_l, beta_r;
	std::tie(alpha, beta_l, beta_r) = _estimate_aggd_param(block);

	// 添加 alpha 和 (beta_l + beta_r) / 2 到特征向量中
	feat.push_back(alpha);
	feat.push_back((beta_l + beta_r) / 2);

	// 定义偏移量
	std::vector<std::vector<int>> shifts = { {0, 1}, {1, 0}, {1, 1}, {1, -1} };

	// 遍历每个偏移量
	// 滚动图像块
	
	for (size_t i = 0; i < shifts.size(); ++i) {
		Mat shifted_block = block.clone();
		Mat cut_block;
		int y_shift = shifts[i][0];   //y_shift 上下行移动
		int x_shift = shifts[i][1];   //x_shift 是行内移动
		if (y_shift != 0)
		{
			if (y_shift > 0)
			{
				cut_block = shifted_block(Rect(0, shifted_block.rows - y_shift, shifted_block.cols, y_shift));
				shifted_block = shifted_block(Rect(0, 0, shifted_block.cols, shifted_block.rows - y_shift));
				vconcat(cut_block, shifted_block, shifted_block);
			}
			else
			{
				cut_block = shifted_block(Rect(0, 0, shifted_block.cols, abs(y_shift)));
				shifted_block = shifted_block(Rect(0, abs(y_shift), shifted_block.cols, shifted_block.rows - abs(y_shift)));
				vconcat(shifted_block, cut_block, shifted_block);
			}
		}
		if (x_shift != 0)
		{
			if(x_shift > 0)
			{
				cut_block = shifted_block(Rect(shifted_block.cols - x_shift, 0, x_shift, shifted_block.rows));
				shifted_block = shifted_block(Rect(0, 0, shifted_block.cols - x_shift, shifted_block.rows));
				hconcat(cut_block, shifted_block, shifted_block);
			}
			else
			{
				cut_block = shifted_block(Rect(0, 0, abs(x_shift), shifted_block.rows));
				shifted_block = shifted_block(Rect(abs(x_shift), 0, shifted_block.cols - abs(x_shift), shifted_block.rows));
				hconcat(shifted_block, cut_block, shifted_block);
			}
		}

		// 计算 alpha、beta_l 和 beta_r 参数
		std::tie(alpha, beta_l, beta_r) = _estimate_aggd_param(block.mul(shifted_block));

		// Eq. 8
		float mean = (beta_r - beta_l) * (std::tgamma(2 / alpha) / std::tgamma(1 / alpha));
		feat.push_back(alpha);
		feat.push_back(mean);
		feat.push_back(beta_l);
		feat.push_back(beta_r);
	}


	return feat;
}


double ScanQualityEvaluator::_CalculateILNIQE(const cv::Mat img, int block_size_h, int block_size_w)
{
	auto st = CMyLog::getCurrentTime();
	// 将图像转换为浮点型,并归一化到[0, 1]范围
	Mat floatImage;
	img.convertTo(floatImage, CV_32F, 1.0f / 255);
	
	// 使用 OpenCV 函数实现颜色转换和亮度调整
	Mat y_Mat;
	transform(floatImage, y_Mat, cv::Matx13f(65.481f, 128.553f, 24.966f));
	y_Mat += 16.0f;


	float* p;
	for (int y = 0; y < y_Mat.rows; ++y) {
		p = y_Mat.ptr<float>(y);
		for (int x = 0; x < y_Mat.cols; ++x) {
			*p = std::round(*p);
			++p;
		}
	}


	int h = y_Mat.rows;
	int w = y_Mat.cols;

	int num_block_h = std::floor(h / block_size_h);
	int num_block_w = std::floor(w / block_size_w);

	int cut_width = block_size_w * num_block_w;
	int cut_height = block_size_h * num_block_h;

	Rect rect(0, 0, cut_width, cut_height);
	y_Mat = y_Mat(rect); 



	vector<float> scales{ 1,2 };
	vector <Mat> distparam;


	for (auto scale : scales)
	{
		Mat mu;
		filter2D(y_Mat, mu, -1, gaussian_window, Point(-1, -1), 0, BORDER_REPLICATE);

		Mat mu_squared = mu.mul(mu);

		Mat img_squared = y_Mat.mul(y_Mat);

		Mat conv_result;
		filter2D(img_squared, conv_result, -1, gaussian_window, Point(-1, -1), 0, BORDER_REPLICATE);

		Mat sigma;

		sqrt(abs(conv_result - mu_squared), sigma);

		Mat img_nomalized = (y_Mat - mu) / (sigma + 1);

		vector <vector<float>> feat;
		vector <float> all_feat;
		for (int idx_w = 0; idx_w < num_block_w; ++idx_w)
		{
			for (int idx_h = 0; idx_h < num_block_h; ++idx_h)
			{
				Rect block_rect(idx_w * block_size_w / scale, idx_h * block_size_h / scale,
					block_size_w / scale, block_size_h / scale);
				Mat block = img_nomalized(block_rect);

				// 计算当前块的特征并存储到 feat 中
				auto vals = _compute_feature(block);
				feat.push_back(vals);
				all_feat.insert(all_feat.end(), vals.begin(), vals.end());
			}
		}


		if (scale == 1)
		{
			resize(y_Mat / 255., y_Mat, Size(), 0.5, 0.5, INTER_LINEAR);
			y_Mat = y_Mat * 255;
		}

		Mat featMat(feat.size(), feat[0].size(), CV_32FC1, all_feat.data());
		distparam.emplace_back(featMat.clone());
	}


	Mat distparam_mat = distparam[0];
	for (int i = 1; i < distparam.size(); ++i)
	{
		hconcat(distparam_mat, distparam[i], distparam_mat);
	}

	Mat mu_distparam;
	reduce(distparam_mat, mu_distparam, 0, REDUCE_AVG);


	Mat cov_distparam;
	calcCovarMatrix(distparam_mat, cov_distparam, mu_distparam, COVAR_NORMAL | COVAR_ROWS | COVAR_SCALE);

	cov_distparam.convertTo(cov_distparam, CV_32F);
	mu_distparam.convertTo(mu_distparam, CV_32F);

	// 计算 niqe quality
	Mat invcov_param = (cov_pris_param + cov_distparam) / 2;
	invert(invcov_param, invcov_param, DECOMP_SVD);

	Mat diff_mat = mu_pris_param - mu_distparam;

	Mat quality = diff_mat * invcov_param * diff_mat.t();
	double quality_value = std::sqrt(quality.at<float>(0, 0));

	std::cout << "Quality: " << quality_value << std::endl;
	做个规约转到2-10转为100-0%   分数越小越好
	//quality_value = quality_value < 2 ? 2 : quality_value;
	//quality_value = quality_value >10 ? 10 : quality_value;

	//quality_value = 1 - (quality_value - 2) / 8;


	return quality_value;

}

int ScanQualityEvaluator::_CalculateILNIQE_Ready(std::string path)
{
	if (mu_pris_param.empty() || cov_pris_param.empty())
	{
		ifstream in_file(path);
		vector<string> lines;
		string line;
		while (getline(in_file, line))
		{
			lines.push_back(line);
		}
		if (lines.size() < 37)
		{
			return -1;
		}
		in_file.close();
		vector<float> mu_pris_param_vec;
		Tool::split_f(lines[0], mu_pris_param_vec, ' ');


		vector<float> cov_pris_param_vec;
		for (int i = 1; i < 37; ++i)
		{
			vector<float> tmp;
			Tool::split_f(lines[i], tmp, ' ');
			cov_pris_param_vec.insert(cov_pris_param_vec.end(), tmp.begin(), tmp.end());
		}

		int param_counts = mu_pris_param_vec.size();
		mu_pris_param = Mat(1, param_counts, CV_32FC1, mu_pris_param_vec.data()).clone();
		cov_pris_param = Mat(param_counts, param_counts, CV_32FC1, cov_pris_param_vec.data()).clone();
	}


	if (gaussian_window.empty())
	{//生成高斯窗口
		gaussian_window = getGaussianKernel(7, 7.0 / 6, CV_32F);

		// 将高斯窗口变为二维矩阵
		gaussian_window = gaussian_window * gaussian_window.t();

		// 归一化高斯窗口
		gaussian_window /= sum(gaussian_window)[0];
	}


	// 计算参数
	for (float i = 0.2; i <= 10.001; i += 0.001) {
		gam.push_back(i);
	}
	std::vector<float> gam_reciprocal(gam.size());
	std::transform(gam.begin(), gam.end(), gam_reciprocal.begin(), [](float x) { return 1.0f / x; });

	r_gam.resize(gam.size());
	for (size_t i = 0; i < gam.size(); ++i) {
		float gamma_reciprocal_2 = std::tgamma(gam_reciprocal[i] * 2);
		float gamma_reciprocal_3 = std::tgamma(gam_reciprocal[i] * 3);
		r_gam[i] = std::pow(gamma_reciprocal_2, 2) / (std::tgamma(gam_reciprocal[i]) * gamma_reciprocal_3);
	}

	return 0;
}


int ScanQualityEvaluator::config(int thread_nums, std::string path)
{
	if (_CalculateILNIQE_Ready(path) != 0)
	{
		return -1;
	}
	m_rgb_img_queue.init();
	m_threads.clear();
	m_img_q_vals.clear();
	setStatus(0);
	for (int i = 0; i < thread_nums; ++i)
	{
		m_threads.push_back(thread(&ScanQualityEvaluator::_Start, this));
	}
	return 0;
}

//raw 转 RGB
int ScanQualityEvaluator::push_back(unsigned char* data, int rows, int cols, int type)
{
	Mat rgbImg;
	if (type == 0)
	{
		const Mat srcImg(rows, cols, CV_8UC1, data);
		cvtColor(srcImg, rgbImg, COLOR_BayerRG2RGB);
	}
	else  //rgb
	{
		rgbImg = Mat(rows, cols, CV_8UC3, data).clone();
	}

	//裁取到最长边1024  加速处理
	int max_size = max(rgbImg.rows, rgbImg.cols);
	double scale = 1024.0 / max_size;
	int new_rows = scale * rgbImg.rows;
	int new_cols = scale * rgbImg.cols;

	//在_img中心裁取new_rows*new_cols的图像
	int x = (rgbImg.cols - new_cols) / 2;
	int y = (rgbImg.rows - new_rows) / 2;
	Mat cut_img = rgbImg(Rect(x, y, new_cols, new_rows));

	//如果不要裁取就解开注释
	//Mat cut_img = rgbImg;
	
	m_rgb_img_queue.push_back(cut_img.clone());
	return 0;
}

int ScanQualityEvaluator::start_calc(int thread_nums, std::string path)
{
	return config(thread_nums, path);
}

double ScanQualityEvaluator::stop_calc()
{
	return _Stop();
}

int ScanQualityEvaluator::setStatus(int status)
{
	m_status = status;
	return m_status;
}

void ScanQualityEvaluator::_Start()
{
	Mat rgbImg;
	while (!(m_status == 1 && m_rgb_img_queue.empty()))
	{
		if (m_rgb_img_queue.pop(rgbImg))
		{
			double ilniqe = _CalculateILNIQE(rgbImg);
			{
				lock_guard<mutex> lk(m_img_q_vals_lock);
				m_img_q_vals.push_back(ilniqe);
			}
		}
		else
		{
			this_thread::sleep_for(10ms);
		}
	}
}

double ScanQualityEvaluator::_Stop()
{
	setStatus(1);
	m_rgb_img_queue.finish();
	for (auto& th : m_threads)
	{
		th.join();
	}
	m_threads.clear();
	int offset = 0;
	sort(m_img_q_vals.begin(), m_img_q_vals.end());

	if (m_img_q_vals.size() > 100)  //超过100个,前20%不参与运算
	{
		offset = m_img_q_vals.size() * 0.2;
	}
	double mean = std::accumulate(m_img_q_vals.begin() + offset, m_img_q_vals.end(), 0.0) / (m_img_q_vals.size() - offset);

	return mean;
}



Param.txt文件的制作(Matlab来生成的)

setDir = fullfile('E:\2024Work\2\ILNIQE\扫描质量评分\all');
imds = imageDatastore(setDir,'FileExtensions',{'.jpg'});

model = fitniqe(imds);

mean = model.Mean;
cov = model.Covariance;


 dlmwrite('Param.txt', mean, ' ');
 dlmwrite('Param.txt', cov,'delimiter', ' ', '-append');
举报

相关推荐

0 条评论