最初的代码自然是大牛写的,我只是在此基础之上,实现分块分割,暂未开启多线程。
引用:
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;
}
更多的交流,欢迎留言。