基于图的图像分割(Graph-BasedImageSegmentation)的分块实现

85 篇文章 4 订阅

最初的代码自然是大牛写的,我只是在此基础之上,实现分块分割,暂未开启多线程。

引用:

Efficient Graph-Based Image Segmentation,IJCV 2004,MIT Code

直接上代码吧,给有同样需求的童鞋参考。

头文件:

#pragma once

#ifdef DLLProvider
#define DLL_API_C extern "C" __declspec(dllexport)
#define DLL_API __declspec(dllexport)
#else
#define DLL_API_C extern "C" __declspec(dllimport)
#define DLL_API __declspec(dllimport)
#endif

//nBgValue = 0/255; block_size = 2048; sigma = 0.0; k = 0.0; min_size = 100;
int ImgSegmentBlock(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned char* pDataDst, int block_size, float sigma, float k, int min_size);
//只能接受8位3通道输入,返回值为分块数目,输出连通域的索引从1开始(nLastIndex必须为0)
int ImgSegmentBlockMark(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned int* pDataDst, int block_size, int nLastIndex, float sigma, float k, int min_size);

cpp文件:

/*
Copyright (C) 2006 Pedro Felzenszwalb

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
*/

#include <cstdio>
#include <cstdlib>
#include <image.h>
#include <misc.h>
#include <pnmfile.h>
#include "segment-image.h"
#include <map>

//#define DLLProvider
#include "imgseg.h"

//参数范围
#define SIGMA_MIN	0.1
#define SIGMA_MAX	0.5
#define K_MIN		5
#define K_MAX		100

#ifndef MIN
#  define MIN(a,b)  ((a) > (b) ? (b) : (a))
#endif

#ifndef MAX
#  define MAX(a,b)  ((a) < (b) ? (b) : (a))
#endif

void inline CheckParameters(int width, int height, float& sigma, float& k)
{
	if (sigma < 1e-5)
	{
		//根据宽高自动设置sigma的值
		sigma = MAX(SIGMA_MIN, MIN(SIGMA_MAX, MAX(width, height) / 10000.0));
	}

	if (k < 1e-5)
	{
		//根据宽高自动设置k的值
		k = MAX(K_MIN, MIN(K_MAX, MAX(width, height) / 50.0));
	}
}

int SegmentPPM(const char* szFilePath, float sigma, float k, int min_size, const char* szDstPath)
{
	if (szFilePath == nullptr)
	{
		return -1;
	}

	printf("loading input image.\n");
	image<rgb> *input = loadPPM(szFilePath);

	int width = input->width();
	int height = input->height();
	//CheckParameters(width, height, sigma, k);

	printf("processing\n");
	int num_ccs; 
	image<rgb> *seg = segment_image(input, sigma, k, min_size, &num_ccs); 
	savePPM(seg, szDstPath);
	printf("got %d components\n", num_ccs);
	printf("done! uff...thats hard work.\n");

	return 0;
}

int ImgSegmentBlock(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned char* pDataDst, int block_size, float sigma, float k, int min_size)
{
	if (pDataSrc == nullptr || pDataDst == nullptr)
	{
		return -1;
	}
	
	CheckParameters(width, height, sigma, k);

	int num_ccs = 0;
	if (block_size <= 0 || width < block_size && height < block_size)
	{
		image<rgb> *input = new image<rgb>(width, height);
		memcpy(input->data, pDataSrc, width * height * 3);
		printf("processing\n");
		image<rgb> *seg = segment_image(input, sigma, k, min_size, &num_ccs); 
		memcpy(pDataDst, seg->data, width * height * 3);
		printf("got %d components\n", num_ccs);
		printf("done! uff...thats hard work.\n");
	}
	else
	{
		//分块处理当前数据块
		int nColIndex = (width - 1) / block_size + 1;		//计算列方向上块数
		int nRowIndex = (height - 1) / block_size + 1;		//计算行方向块数

		int nBlockWidth = block_size;						//当前块宽度
		int nBlockHeight = block_size;						//当前块高度
		unsigned char* pDataBlock = new unsigned char[nBlockWidth * nBlockHeight * 3]();
		unsigned char* pDataBlockDst = new unsigned char[nBlockWidth * nBlockHeight * 3]();
		for (int nRI = 0; nRI < nRowIndex; nRI++)
		{
			unsigned char* pRDataSrc = pDataSrc + nRI * block_size * width * 3;
			unsigned char* pRDataDst = pDataDst + nRI * block_size * width * 3;
			for (int nCI = 0; nCI < nColIndex; nCI++)
			{
				nBlockWidth = block_size;
				nBlockHeight = block_size;
				//行列末尾小块处理
				if (nCI == nColIndex - 1 && width % block_size != 0)nBlockWidth = (width) % block_size;
				if (nRI == nRowIndex - 1 && height % block_size != 0)nBlockHeight = (height) % block_size;

				//得到每一块的数据
				unsigned char* pCDataSrc = pRDataSrc + nCI * block_size * 3;
				unsigned char* pCDataDst = pRDataDst + nCI * block_size * 3;
				for (size_t j = 0; j < nBlockHeight; ++j)
				{
					unsigned char* pSubDataSrc = pCDataSrc + j * width * 3;
					unsigned char* pSubBlockDataDst = pDataBlock + j * nBlockWidth * 3;
					memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
				}

				num_ccs += ImgSegmentBlock(pDataBlock, nBlockWidth, nBlockHeight, nBgValue, pDataBlockDst, -1, sigma, k, min_size);

				//将目标结果覆盖到当前区域
				for (size_t j = 0; j < nBlockHeight; ++j)
				{
					unsigned char* pSubDataDst = pCDataDst + j * width * 3;
					unsigned char* pSubBlockDataDst = pDataBlockDst + j * nBlockWidth * 3;
					memcpy(pSubDataDst, pSubBlockDataDst, nBlockWidth * 3);
				}
			}
		}

		delete[] pDataBlock;
		delete[] pDataBlockDst;
	}

	return num_ccs;
}

int ImgSegmentBlockMark(unsigned char* pDataSrc, int width, int height, int nBgValue,
	unsigned int* pDataDst, int block_size, int nLastIndex, float sigma, float k, int min_size)
{
	if (pDataSrc == nullptr || pDataDst == nullptr)
	{
		return -1;
	}

	CheckParameters(width, height, sigma, k);

	int num_ccs = 0;
	if (block_size <= 0 || width < block_size && height < block_size)
	{
		image<rgb> *input = new image<rgb>(width, height);
		memcpy(input->data, pDataSrc, width * height * 3);
		printf("processing\n");

		universe* u = segment_image(input, sigma, k, min_size); 
		int num_ccs = u->num_sets();

		std::map<int, int> mvs;
		for (size_t j = 0; j < height; ++j)
		{
			unsigned int* data = pDataDst + j * width;
			for (size_t i = 0; i < width; ++i)
			{
				int comp = u->find(j * width + i);
				if (mvs.find(comp) == mvs.end())
				{
					mvs.insert(std::make_pair(comp, ++nLastIndex));
				}
				data[i] = mvs[comp];
			}
		}

		printf("got %d components\n", num_ccs);
		printf("done! uff...thats hard work.\n");

		delete input;
		delete u;

		return num_ccs;
	}
	else
	{
		//分块处理当前数据块
		int nColIndex = (width - 1) / block_size + 1;		//计算列方向上块数
		int nRowIndex = (height - 1) / block_size + 1;		//计算行方向块数

		int nBlockWidth = block_size;						//当前块宽度
		int nBlockHeight = block_size;						//当前块高度
		unsigned char* pDataBlock = new unsigned char[nBlockWidth * nBlockHeight * 3]();
		unsigned int* pDataBlockDst = new unsigned int[nBlockWidth * nBlockHeight]();
		for (int nRI = 0; nRI < nRowIndex; nRI++)
		{
			unsigned char* pRDataSrc = pDataSrc + nRI * block_size * width * 3;
			unsigned int* pRDataDst = pDataDst + nRI * block_size * width;
			for (int nCI = 0; nCI < nColIndex; nCI++)
			{
				nBlockWidth = block_size;
				nBlockHeight = block_size;
				//行列末尾小块处理
				if (nCI == nColIndex - 1 && width % block_size != 0)nBlockWidth = (width) % block_size;
				if (nRI == nRowIndex - 1 && height % block_size != 0)nBlockHeight = (height) % block_size;

				//得到每一块的数据
				unsigned char* pCDataSrc = pRDataSrc + nCI * block_size * 3;
				unsigned int* pCDataDst = pRDataDst + nCI * block_size;
				for (size_t j = 0; j < nBlockHeight; ++j)
				{
					unsigned char* pSubDataSrc = pCDataSrc + j * width * 3;
					unsigned char* pSubBlockDataDst = pDataBlock + j * nBlockWidth * 3;
					memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
				}

				nLastIndex += ImgSegmentBlockMark(pDataBlock, nBlockWidth, nBlockHeight, nBgValue, pDataBlockDst, -1, nLastIndex, sigma, k, min_size);

				//将目标结果覆盖到当前区域
				for (size_t j = 0; j < nBlockHeight; ++j)
				{
					unsigned int* pSubDataDst = pCDataDst + j * width;
					unsigned int* pSubBlockDataDst = pDataBlockDst + j * nBlockWidth;
					memcpy(pSubDataDst, pSubBlockDataDst, nBlockWidth * sizeof(int));
				}
			}
		}

		delete[] pDataBlock;
		delete[] pDataBlockDst;
	}

	return nLastIndex;
}

更多的交流,欢迎留言。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值