基於圖的圖像分割(Graph-BasedImageSegmentation)的分塊實現

最初的代碼自然是大牛寫的,我只是在此基礎之上,實現分塊分割,暫未開啓多線程。

引用:

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;
}

更多的交流,歡迎加入 暗號271888395

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章