Color Coherence Vector

之前做一个iOS OCR的时候用到过的,ccv可以理解为一个比较复杂的直方图匹配,这个版本是从 http://d.hatena.ne.jp/ytakano/comment/20100714/1279090202转载过来的,ccv的论文见ACM--Comparing Images Using Color Coherence Vectors,paper里面有个比较简单的例子。这个code需要boost和opencv2.0以上版本,估计看到这篇blog的人都会配置。半成品代码,最后也没有用到iOS上面,一方面,ARM平台的计算能力还是欠佳,添加代码以后匹配很慢,另一方面,自己改造调试了另外类似一个匹配方法,效果还不错,boss也挺喜欢。代码的结构很清晰的,如果有不懂这个代码的,欢迎留言。
 
/*Color Coherence Vector*/


//#include <stdint.h>
#include "opencv2.1/include/cv.h"
#include "opencv2.1/include/highgui.h"
#include <boost/shared_array.hpp>
//#include <shared_array.hpp>
#include <boost/unordered_map.hpp>
#include<boost/cstdint.hpp>
//#include "C:\Program Files (x86)\boost_1_46_100\boost_1_46_1\boost\shared_array.hpp"
//#include "C:\Program Files (x86)\boost_1_46_100\boost_1_46_1\boost\unordered\unordered_map.hpp"
#pragma comment(lib, "cxcore210d")
#pragma comment(lib, "cv210d")
#pragma comment(lib, "highgui210d")
#define NUM_CCV_COLOR (4 * 4 * 4)
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef unsigned char   uint8_t;

struct feature_ccv {
	typedef boost::shared_array<float> float_arr;
	float_arr m_alpha;
	float_arr m_beta;
};

union rgb {
	uint32_t m_color32;
	uint8_t  m_color8[4];

	bool operator== (const rgb &rhs) { return m_color32 == rhs.m_color32; }
};

struct label_info {
	rgb m_color;
	int m_count;
	uint32_t m_alias;
};

static const int ccv_width  = 240;
static const int ccv_height = 160;
static const int t_ccv = 25;

inline
	void
	get_rgb(rgb &color, const cv::Mat &img, int x, int y)
{
	uint8_t r, b, g;
	int idx = (x + y * ccv_width) * 3;

	b = img.data[idx];
	g = img.data[idx + 1];
	r = img.data[idx + 2];

	b >>= 6;//devide by 64
	g >>= 6;
	r >>= 6;

	color.m_color8[0] = b;
	color.m_color8[1] = g;
	color.m_color8[2] = r;
	color.m_color8[3] = 0;
}

inline
	int
	rgb2idx(const rgb &color)
{
	return (int)color.m_color8[0] | (int)color.m_color8[1] << 2 |
		(int)color.m_color8[2] << 4;
}

inline
	uint32_t
	find_label(uint32_t label, boost::unordered_map<uint32_t, label_info> &labels)
{
	boost::unordered_map<uint32_t, label_info>::iterator it;

	for (it = labels.find(label); label != it->second.m_alias;) {
		label = it->second.m_alias;
		it = labels.find(label);
	}

	return label;
}

void
	ccv(const cv::Mat &src, feature_ccv &ret)
{
	boost::shared_array<uint32_t>  labeled;
	boost::unordered_map<uint32_t, label_info> labels;
	cv::Mat resized;
	int i;

	if (src.channels() != 3)
		return;

	cv::resize(src, resized, cv::Size(ccv_width, ccv_height));
	cv::GaussianBlur(resized, resized, cv::Size(3, 3), 0);

	ret.m_alpha = feature_ccv::float_arr(new float[NUM_CCV_COLOR]);
	ret.m_beta  = feature_ccv::float_arr(new float[NUM_CCV_COLOR]);

	for (i = 0; i < NUM_CCV_COLOR; i++) {
		ret.m_alpha[i] = 0.0f;
		ret.m_beta[i]  = 0.0f;
	}

	label_info info;
	rgb        color;
	uint32_t   label;
	int        size;

	size = ccv_width * ccv_height;
	labeled = boost::shared_array<uint32_t>(new uint32_t[size]);

	get_rgb(color, resized, 0, 0);

	label = 0;

	labeled[0] = label;

	info.m_color = color;
	info.m_alias = label;
	info.m_count = 1;

	labels[label] = info;

	int x, y;
	for (x = 1; x < ccv_width; x++) {
		rgb color_here, color_left;

		get_rgb(color_here, resized, x,     0);//x, y
		get_rgb(color_left, resized, x - 1, 0);

		if (color_here.m_color32 == color_left.m_color32) {//m_color32 = m_color8[2]*256^2 + m_color8[1]*256^1 + m_color8[0]*256^0
			labels[label].m_count++;
			labeled[x] = label;
		} 
		else
		{
			label++;
			labeled[x] = label;

			info.m_color = color_here;
			info.m_alias = label;
			info.m_count = 1;

			labels[label] = info;
		}
	}

	for (y = 1; y < ccv_height; y++) {
		rgb c_here, c_left, c_above, c_above_l, c_above_r;

		c_left.m_color32    = 0xffffffff;
		c_above_l.m_color32 = 0xffffffff;
		get_rgb(c_above, resized, 0, y - 1);

		for (x = 0; x < ccv_width; x++) {
			get_rgb(c_here, resized, x, y);

			if (x + 1 < ccv_width)
				get_rgb(c_above_r, resized, x + 1, y - 1);
			else
				c_above_r.m_color32 = 0xffffffff;


			uint32_t same[4];
			uint32_t l;
			int      num_same = 0;

			if (c_here == c_left) {
				l = labeled[x - 1 + y * ccv_width];
				same[num_same] = find_label(l, labels);
				num_same++;
			}

			if (c_here == c_above) {
				l = labeled[x + (y - 1) * ccv_width];
				same[num_same] = find_label(l, labels);
				num_same++;
			}

			if (c_here == c_above_l) {
				l = labeled[x - 1 + (y - 1) * ccv_width];
				same[num_same] = find_label(l, labels);
				num_same++;
			}

			if (c_here == c_above_r) {
				l = labeled[x + 1 + (y - 1) * ccv_width];
				same[num_same] = find_label(l, labels);
				num_same++;
			}

			if (num_same > 0) {
				boost::unordered_map<uint32_t,
					label_info>::iterator it1, it2;
				uint32_t label_min = same[0];

				for (i = 1; i < num_same; i++) {
					if (same[i] < label_min) {
						label_min = same[i];
					}
				}

				it1 = labels.find(label_min);
				it1->second.m_count++;

				for (i = 0; i < num_same; i++) {
					if (label_min < same[i]) {
						it2 = labels.find(same[i]);

						int count = it2->second.m_count;

						it2->second.m_alias = label_min;
						it2->second.m_count = 0;

						it1->second.m_count += count;
					}
				}

				labeled[x + y * ccv_width] = label_min;
			} else {
				label++;
				labeled[x + y * ccv_width] = label;

				info.m_color = c_here;
				info.m_alias = label;
				info.m_count = 1;

				labels[label] = info;
			}
		}

		c_left    = c_here;
		c_above   = c_above_r;
		c_above_l = c_above;
	}

	boost::unordered_map<uint32_t, label_info>::iterator it;
	for (it = labels.begin(); it != labels.end(); ++it) {
		int idx;
		idx = rgb2idx(it->second.m_color);

		if (it->second.m_count > t_ccv) {//t_ccv is the t(tao)
			ret.m_alpha[idx] += it->second.m_count;
		} else {
			ret.m_beta[idx] += it->second.m_count;
		}
	}

	float num_pix = ccv_width * ccv_height;
	for (i = 0; i < NUM_CCV_COLOR; i++) {
		ret.m_alpha[i] /= num_pix;
		ret.m_beta[i]  /= num_pix;
	}
}

bool
	get_ccv_feat(const char *file, feature_ccv &feat)
{
	try {
		cv::Mat colorImage = cv::imread(file, 1);
		if(colorImage.empty())
			return false;

		ccv(colorImage, feat);
	} catch (...) {
		return false;
	}

	return true;
}
float dist(const float *v1, const float *v2, int len)
{
	float dist = 0.0;
	int   i;

	for (i = 0; i < len; i++) {
		float d;

		d  = v1[i] - v2[i];
		d *= d;

		dist += d;
	}

	return dist;
}

int main()
{
	feature_ccv feat1, feat2;
	get_ccv_feat("3.jpg", feat1);
	get_ccv_feat("422.jpg", feat2);
	for (int i = 0; i < NUM_CCV_COLOR; i++) {
		std::cout << feat1.m_alpha[i] <<"		"<<feat2.m_alpha[i]<< std::endl;
		//std::cout <<  << std::endl;
	}
	float distance;
	distance = dist(feat1.m_alpha.get(), feat2.m_alpha.get(), NUM_CCV_COLOR);
	distance += dist(feat2.m_beta.get(), feat2.m_beta.get(), NUM_CCV_COLOR);
	distance = sqrtf(distance);
	std::cout<<distance<<std::endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值