C++实现图像数字水印提取

分享一下之前做过的基于DCT变换的水印提取程序。开始先用python实现了一下,但发现提取的速度太慢,对100KB左右的单幅图像处理速度在50ms左右,于是用C++重写了一下,用到了opencv3.4.5,和NumCpp插件来实现python中numpy中的数学计算功能。

定义了一个WM类,用来做水印提取和相关的计算,先看头文件

#pragma once
#ifndef __WM__
#define __WM__

#include 
#include "stdlib.h"
#include 
#include 
#include 
#include 
#include 

#include "NumCpp.hpp"
#ifdef _DEBUG  
#pragma comment(lib,"opencv_world345d.lib") 
#else
#pragma comment(lib,"opencv_world345.lib")
#endif
using namespace std;
using namespace cv;
using namespace nc;

class WM
{

private:
	nc::NdArray<int> _gene_signature();

	double calc_sim(nc::NdArray<int>sig1, list<nc::NdArray<int>> sig2s);

	nc::NdArray<int> TransNdArrayBoolToInt(nc::NdArray<bool> src);

	int GetSum(nc::NdArray<bool> src);

	double extract(Mat ori_wmimage, int key);

	list<nc::NdArray<int>> inner_extract(Mat rgbChannels,int size, nc::NdArray<int> signature);

	Mat ExctArray(Mat srcArray, int i, int j, int size);

public:
	bool GetSig(char* imgName);
};

#endif

通过计算获取到水印图像的特征向量,与目标图像进行校验,来判别图像中是否含有目标水印,是一种有参照的提取方法。

#include "WM.h"

nc::NdArray<int> WM::_gene_signature() {
	Mat new_wm;
	cv::Size cvSize;
	cvSize.height = size;
	cvSize.width = size;
	cv::resize(wm, new_wm,cvSize);

	auto n_wm = nc::NdArray<nc::uint8>(new_wm.data, new_wm.rows, new_wm.cols);
	nc::NdArray<double> wU;
	nc::NdArray<double> wS;
	nc::NdArray<double> wV;
	nc::linalg::svd(n_wm.astype<double>(),wU,wS,wV);

	auto sumU = nc::sum<double>(wU, nc::Axis::ROW);
	auto sumV = nc::sum<double>(wV, nc::Axis::ROW);

	auto sumU_mid = nc::median(sumU);
	auto sumV_mid = nc::median(sumV);

	for (int i = 0; i < size; ++i)
	{
		if (sumU[i] > sumU_mid[i])
		{
			sumU[i] = 1;
		}
		else
		{
			sumU[i] = 0;
		}
	}

	for (int i = 0; i < size; ++i)
	{
		if (sumV[i] > sumV_mid[i])
		{
			sumV[i] = 1;
		}
		else
		{
			sumV[i] = 0;
		}
	}



	auto uv_xor = nc::logical_xor(sumU, sumV);
	nc::NdArray<int> int_uv_xor = TransNdArrayBoolToInt(uv_xor);
	nc::random::seed(key);
	auto seq = nc::random::randInt<int>({1,256},0,2);



	auto signature = nc::logical_xor(int_uv_xor, seq);
	auto sqrts = int(nc::sqrt(size));
	nc::NdArray<int> int_signature = TransNdArrayBoolToInt(signature);

	int_signature.reshape(sqrts,sqrts);
	
	//cout << "int_signature is " << int_signature << endl;
	return int_signature;
	//return int_signature;

}

nc::NdArray<int> WM::TransNdArrayBoolToInt(nc::NdArray<bool> src) {
	auto rt = nc::NdArray<int>(1,256)=0;

	try {
		for (int i = 0; i < 256; ++i)
		{
			if (src[i] == true)
			{
				rt[i] = 1;
			}
			else
			{
				rt[i] = 0;
			}
		}
		return rt;
	}
	catch(exception ex){
		wprintf_s(L"the error is %s\n",ex);
	}
}

int WM::GetSum(nc::NdArray<bool> src) {
	int rt = 0;
	for (int i = 0; i < 256; ++i)
	{
		if (src[i] == true)
		{
			++rt;
		}
	}
	return rt;
}

double WM::calc_sim(nc::NdArray<int>sig1, list<nc::NdArray<int>> sig2s)
{
	double rt = 0.0;
	double sim = 0.0;
	int n = 0;
	auto ite = sig2s.begin(), ite_end = sig2s.end();
	while (ite != ite_end) {
		++n;
		if (n == 16)
		{
			break;
		}
		++ite;

		nc::NdArray<int> sig2 = *ite;
		nc::NdArray<bool> tempRT = (nc::equal<int>(sig1, sig2));

		int match_cnt = GetSum(tempRT);


		sim = match_cnt / 256.0;
		rt = max(rt, sim);

	}
	return rt;

}

double WM::extract(Mat ori_wmimage, int key) {
	std::vector<cv::Mat> rgbChannels(3);
	split(ori_wmimage, rgbChannels);
	nc::NdArray<int> signature  = _gene_signature();
	signature = signature.flatten();
	list<nc::NdArray<int>> ext_sig = inner_extract(rgbChannels[0], 2 ,signature);
	//cout << "rgb:"<
	return calc_sim(signature,ext_sig);
}

Mat WM::ExctArray(Mat srcArray, int i, int j, int size){
	Mat rtMat = Mat::zeros(size, size, CV_8UC1);

	if (channels == 3) {
		for (int m = 0; m < size; ++m)
		{
			for (int n = 0; n < size; ++n)
			{
				rtMat.at<Vec3b>(m, n)[0] = srcArray.at<Vec3b>(i, j)[0];
				rtMat.at<Vec3b>(m, n)[1] = srcArray.at<Vec3b>(i, j)[1];
				rtMat.at<Vec3b>(m, n)[2] = srcArray.at<Vec3b>(i, j)[2];
			}
		}
	}
	else
	{
	    rtMat.at<uchar>(0, 0) = srcArray.at<uchar>(i, j);
	    rtMat.at<uchar>(0, 1) = srcArray.at<uchar>(i, j+1);
	    rtMat.at<uchar>(1, 0) = srcArray.at<uchar>(i+1, j);
	    rtMat.at<uchar>(1, 1) = srcArray.at<uchar>(i+1, j+1);
	}
	
	return rtMat;
}

list<nc::NdArray<int>> WM::inner_extract(Mat rgbChannels, int size, nc::NdArray<int> signature) {
	int sig_size = 16;
	int width = rgbChannels.rows;
	int height = rgbChannels.cols;
	list<nc::NdArray<int>> RT;
	int embed_pos_x[4] = { 0,width - sig_size * size ,0,width - sig_size * size };
	int embed_pos_y[4] = { 0,0,height - sig_size * size ,height - sig_size * size };
	int k = 0;
	for (int m = 0; m < 4; ++m)
	{
		nc::NdArray<int>ext_sig = nc::zeros<int>(1,256);

		
		for (int i = embed_pos_x[m]; i < embed_pos_x[m] + sig_size * size; i += size)
		{
			int num = 0;
			for (int j = embed_pos_y[m]; j < embed_pos_y[m] + sig_size * size; j += size)
			{
				Mat v;
				Mat tempArray = ExctArray(rgbChannels, i,j, size);
				
				tempArray.convertTo(tempArray, CV_32F, 255.0/255.0);

				dct(tempArray,v);
				if (v.at<float>(1, 1) > 5) {
					++num;
					ext_sig[nc::floor((i - embed_pos_x[m]) / size)*sig_size + nc::floor((j - embed_pos_y[m]) / size)] = 1;
				}
			}
		}
		RT.push_back(ext_sig);
		nc::NdArray<int>ext_sig_arr = nc::NdArray<int>(ext_sig).reshape(sig_size, sig_size);
		RT.push_back(nc::rot90<int>(ext_sig_arr,1).flatten());
		RT.push_back(nc::rot90<int>(ext_sig_arr,2).flatten());
		RT.push_back(nc::rot90<int>(ext_sig_arr,3).flatten());

	}
	//delete[] embed_pos_x;
	//delete[] embed_pos_y;
	
	return RT;
}

bool WM::GetSig(char* imgName){
	Mat src = imread(imgName, 0);

	if (!src.data)  //or == if(src.empty())
	{
		cout << "Could not open or find the image" << endl;
		return false;
	}


	double rt = extract(src,10);
	cout << "rt is " << rt << endl;
	if (rt > 0.7){
		return true;
	}
	else {
		return false;
	}
}

你可能感兴趣的:(opencv,计算机视觉)