图片相似度比较

54 篇文章 0 订阅
// ImageCmp.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "ImageSimilar.h"
#include <iostream>
#include <Psapi.h>

int _tmain(int argc, _TCHAR* argv[])
{
	ImageSimilar::initGdiPlus();

	HANDLE h = GetCurrentProcess();
	for (int i = 1; i <= 100; ++i)
	{
		PROCESS_MEMORY_COUNTERS mem = { 0 };
		GetProcessMemoryInfo(h, &mem, sizeof(mem));
		int memSize = mem.WorkingSetSize / 1024 * 1024;

		auto start = std::chrono::system_clock::now();

		float val = ImageSimilar::getSimilar("1.png", "2.png");

		auto end = std::chrono::system_clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
		double cost = double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den;
		std::cout << "val=" << val << " 耗时:" << cost << "秒" << " memSize=" << memSize<< std::endl;
	}

	ImageSimilar::unInitGdiPlus();
	getchar();
	return 0;
}

#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;

namespace ImageSimilar
{
	typedef struct tagIStreamBmp
	{
		IStream *pIStream;
		Bitmap *pBitmap;
		tagIStreamBmp()
		{
			pIStream = NULL;
		}
	}SIStreamBmp, *PSIStreamBmp;

	GdiplusStartupInput gdiplusstartupinput;
	ULONG_PTR gdiplustoken;

	void initGdiPlus()
	{
		GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);
	}

	void unInitGdiPlus()
	{
		GdiplusShutdown(gdiplustoken);
	}

	bool getStreamBmp(SIStreamBmp& iStreamBmp, char* szData, int dataLen)
	{
		HGLOBAL hMemBmp = GlobalAlloc(GMEM_FIXED, dataLen);
		if (hMemBmp == NULL) return false;
		CreateStreamOnHGlobal(hMemBmp, TRUE, &iStreamBmp.pIStream);
		if (iStreamBmp.pIStream == NULL)
		{
			return false;
		}
		BYTE* bData = (BYTE *)GlobalLock(hMemBmp); // 获得内存块首地址
		memcpy(bData, szData, dataLen);
		GlobalUnlock(hMemBmp);

		iStreamBmp.pBitmap = Bitmap::FromStream(iStreamBmp.pIStream);
		
		//GlobalFree(hMemBmp); // 需要释放吗?
		return true;
	}

	int getFileSize(char* szFile)
	{
		size_t size = 0;
		std::ifstream f;
		f.open(szFile, std::ios::binary | std::ios::in);
		if (f.is_open())
		{
			f.seekg(0, std::ios::end);
			size = f.tellg();
			f.close();
		}
		return size;
	}

	float getSimilar2(char* szData1, int dataLen1, char* szData2, int dataLen2)
	{
		if (szData1 == NULL || dataLen1 <= 0) return 0;
		if (szData2 == NULL || dataLen2 <= 0) return 0;

		SIStreamBmp sBmp1;
		SIStreamBmp sBmp2;
		if (!getStreamBmp(sBmp1, szData1, dataLen1)) return 0;
		if (!getStreamBmp(sBmp2, szData2, dataLen2)) return 0;

		if (sBmp1.pBitmap->GetWidth() != sBmp2.pBitmap->GetWidth()) return 0;
		if (sBmp1.pBitmap->GetHeight() != sBmp2.pBitmap->GetHeight()) return 0;

		Gdiplus::Color c1;
		Gdiplus::Color c2;

		// 逐个像素比较
		int xMax = sBmp1.pBitmap->GetWidth();
		int yMax = sBmp1.pBitmap->GetHeight();
		int same = 0;
		for (size_t x = 0; x < xMax; x++)
		{
			for (size_t y = 0; y < yMax; y++)
			{
				sBmp1.pBitmap->GetPixel(x, y, &c1);
				sBmp2.pBitmap->GetPixel(x, y, &c2);
				if (c1.GetValue() == c2.GetValue())
				{
					same += 1;
				}
			}
		}

		delete sBmp1.pBitmap;
		delete sBmp2.pBitmap;
		//::delete sBmp1.pBitmap;
		//::delete sBmp2.pBitmap;
		sBmp1.pIStream->Release();
		sBmp2.pIStream->Release();
		return float(same) / float(xMax*yMax);
	}

	float getSimilar(char* szFile1, char* szFile2)
	{
		int size1 = getFileSize(szFile1);
		int size2 = getFileSize(szFile2);
		if (size1 <= 0) return 0;
		if (size2 <= 0) return 0;
		char* szData1 = new char[size1];
		char* szData2 = new char[size2];
		std::ifstream f1;
		std::ifstream f2;
		f1.open(szFile1, std::ios::binary | std::ios::in);
		f2.open(szFile2, std::ios::binary | std::ios::in);
		if (f1.is_open())
		{
			f1.read(szData1, size1);
			f1.close();
		}
		if (f2.is_open())
		{
			f2.read(szData2, size2);
			f2.close();
		}
		float val = getSimilar2(szData1, size1, szData2, size2);
		if (szData1 != NULL) delete[] szData1;
		if (szData2 != NULL) delete[] szData2;
		return val;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

friendan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值