代碼是基於上一篇文章基於圖的圖像分割(Graph-BasedImageSegmentation)的分塊實現的修改,主要是增加多線程,以及分塊之後結果的合併的功能,代碼相對複雜,因爲關聯了其他源文件,所以代碼僅供參考。
先上頭文件:
#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 ImgSegBlock(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開始
int ImgSegBlockMark(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned int* pDataDst, int block_size, float sigma, float k, int min_size);
//使用K均值將得到的碎塊進行合併
int KMeansSegment(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned int* pDataDst, int block_size, 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>
#include <omp.h>
//#define DLLProvider
#include "imgseg.h"
#include "..\FindBoundary.h"
#include "arealines.h"
#include "k-means.h"
//#include "Log.h"
#include "..\src\StdStrFile.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
#define imData(pData, x, y, width) (pData[(y) * (width) + x])
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));
sigma = 0.0;
}
if (k < 1e-5)
{
//根據寬高自動設置k的值
//k = MAX(K_MIN, MIN(K_MAX, MAX(width, height) / 50.0));
k = 0.0;
}
}
//調試用
void inline SaveBufferPPM(unsigned char* pDataSrc, int width, int height, const char* szFilePath = "D:\\a.ppm")
{
image<rgb> *input = new image<rgb>(width, height);
memcpy(input->data, pDataSrc, width * height * 3);
savePPM(input, szFilePath);
delete input;
}
void inline SaveBoundBufferPPM(unsigned char* pDataSrc, int width, int height, const char* szFilePath = "D:\\b.ppm")
{
image<rgb> *input = new image<rgb>(width, height);
for (size_t j = 0; j < height; ++j)
{
unsigned char* pSubData = pDataSrc + j * width;
rgb* data = input->data + j * width;
for (size_t i = 0; i < width; ++i)
{
if (pSubData[i])
{
data[i].r = data[i].g =data[i].b = 255;
}
else
{
data[i].r = data[i].g =data[i].b = 0;
}
}
}
savePPM(input, szFilePath);
delete input;
}
void inline SaveBufferPPM(unsigned int* pDataSrc, int width, int height, const char* szFilePath = "D:\\seg.ppm")
{
// pick random colors for each component
rgb *colors = new rgb[width*height]();
for (int i = 0; i < width*height; i++)
colors[i] = random_rgb();
image<rgb> *input = new image<rgb>(width, height);
for (size_t j = 0; j < height; ++j)
{
unsigned int* pInt = pDataSrc + j * width;
rgb* data = input->data + j * width;
for (size_t i = 0; i < width; ++i)
{
data[i] = colors[pInt[i]];
}
}
savePPM(input, szFilePath);
delete input;
}
int SegmentPPM(const char* szFilePath, float sigma, float k, int min_size, const char* szDstPath)
{
if (szFilePath == nullptr || szDstPath == 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 = 0;
uchar* pBound = new uchar[width * height]();
image<rgb> *seg = segment_image(input, sigma, k, min_size, &num_ccs, pBound);
delete[] pBound;
savePPM(seg, szDstPath);
delete seg;
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, uchar* pBound, unsigned char* pDataDst, int block_size, float sigma, float k, int min_size)
{
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, pBound);
memcpy(pDataDst, seg->data, width * height * 3);
delete input;
delete seg;
printf("got %d components\n", num_ccs);
printf("done! uff...thats hard work.\n");
}
else
{
//分塊處理當前數據塊,最後一行和最後一列要合併到上一塊進行處理
int nColIndex = MAX(1, (width /*- 1*/) / block_size /*+ 1*/); //計算列方向上塊數
int nRowIndex = MAX(1, (height /*- 1*/) / block_size /*+ 1*/); //計算行方向塊數
//定義核心數個buffer
int nThreadNum = omp_get_num_procs();
int nBISum = nColIndex * nRowIndex;
#pragma omp parallel for num_threads(nThreadNum) reduction(+:num_ccs)
for (int nBI = 0; nBI < nBISum; nBI++)
{
int nRI = nBI / nColIndex;
int nCI = nBI % nColIndex;
unsigned char* pRDataSrc = pDataSrc + nRI * block_size * width * 3;
unsigned char* pRDataDst = pDataDst + nRI * block_size * width * 3;
uchar* pRDataBound = pBound + nRI * block_size * width;
int nCurTh = nBI % nThreadNum;
int nBlockWidth = block_size;
int nBlockHeight = block_size;
//行列末尾塊處理
if (nCI == nColIndex - 1 && width % block_size != 0)nBlockWidth = (width) % block_size + block_size;
if (nRI == nRowIndex - 1 && height % block_size != 0)nBlockHeight = (height) % block_size + block_size;
nBlockWidth = MIN(nBlockWidth, width);
nBlockHeight = MIN(nBlockHeight, height);
//每個線程獨立管理內存
unsigned char* pDataBlockSrc = new unsigned char[nBlockWidth * nBlockHeight * 3]();
unsigned char* pDataBlockDst = new unsigned char[nBlockWidth * nBlockHeight * 3]();
unsigned char* pDataBound = new uchar[nBlockWidth * nBlockHeight]();
//輸出緩存必須清零
//memset(pDataBlockSrc, 0, nBlockWidth * nBlockHeight * 3);
//memset(pDataBlockDst, 0, nBlockWidth * nBlockHeight * 3);
//memset(pDataBound, 0, nBlockWidth * nBlockHeight);
//得到每一塊的數據
unsigned char* pCDataSrc = pRDataSrc + nCI * block_size * 3;
unsigned char* pCDataDst = pRDataDst + nCI * block_size * 3;
uchar* pCDataBound = pRDataBound + nCI * block_size;
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned char* pSubDataSrc = pCDataSrc + j * width * 3;
unsigned char* pSubBlockDataDst = pDataBlockSrc + j * nBlockWidth * 3;
uchar* pSubDataBoundSrc = pCDataBound + j * width;
uchar* pSubDataBoundDst = pDataBound + j * nBlockWidth;
memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
memcpy(pSubDataBoundDst, pSubDataBoundSrc, nBlockWidth);
}
num_ccs += ImgSegmentBlock(pDataBlockSrc, nBlockWidth, nBlockHeight, pDataBound, 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[] pDataBlockSrc;
delete[] pDataBlockDst;
delete[] pDataBound;
}
}
return num_ccs;
}
int ImgSegmentBlockMark(unsigned char* pDataSrc, int width, int height, uchar* pBound,
unsigned int* pDataDst, int block_size, int nLastIndex, float sigma, float k, int min_size)
{
CheckParameters(width, height, sigma, k);
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_u(input, sigma, k, min_size, pBound);
int num_ccs = u->num_sets();
//輸出內存必須覆蓋,因爲邊界部分不會賦值
memset(pDataDst, 0, width * height * sizeof(int));
std::map<int, int> mvs;
for (size_t j = 0; j < height; ++j)
{
unsigned int* data = pDataDst + j * width;
uchar* bound = pBound + j * width;
for (size_t i = 0; i < width; ++i)
{
if (!bound[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];
}
else
{
--num_ccs;
}
}
}
printf("got %d components\n", num_ccs);
printf("done! uff...thats hard work.\n");
delete input;
delete u;
return num_ccs;
}
else
{
//分塊處理當前數據塊
int nColIndex = MAX(1, (width /*- 1*/) / block_size /*+ 1*/); //計算列方向上塊數
int nRowIndex = MAX(1, (height /*- 1*/) / block_size /*+ 1*/); //計算行方向塊數
//定義核心數個buffer
int nThreadNum = omp_get_num_procs();
int nBlockWidthB = block_size * 2; //當前塊寬度
int nBlockHeightB = block_size * 2; //當前塊高度
unsigned char** pDataBlock = new unsigned char*[nThreadNum]();
unsigned int** pDataBlockDst = new unsigned int*[nThreadNum]();
uchar** pDataBound = new uchar*[nThreadNum]();
for (int i = 0; i < nThreadNum; ++i)
{
pDataBlock[i] = new unsigned char[nBlockWidthB * nBlockHeightB * 3]();
pDataBlockDst[i] = new unsigned int[nBlockWidthB * nBlockHeightB]();
pDataBound[i] = new uchar[nBlockWidthB * nBlockHeightB]();
}
int nBISum = nColIndex * nRowIndex;
int* nCompCount = new int[nBISum]();
#pragma omp parallel for num_threads(nThreadNum)
for (int nBI = 0; nBI < nBISum; nBI++)
{
int nRI = nBI / nColIndex;
int nCI = nBI % nColIndex;
unsigned char* pRDataSrc = pDataSrc + nRI * block_size * width * 3;
unsigned int* pRDataDst = pDataDst + nRI * block_size * width;
uchar* pRDataBound = pBound + nRI * block_size * width;
//根據線程ID決定訪問的內存塊
int ti = omp_get_thread_num()/* % nThreadNum*/;
int nBlockWidth = block_size;
int nBlockHeight = block_size;
//行列末尾小塊處理
if (nCI == nColIndex - 1 && width % block_size != 0)nBlockWidth = (width) % block_size + block_size;
if (nRI == nRowIndex - 1 && height % block_size != 0)nBlockHeight = (height) % block_size + block_size;
nBlockWidth = MIN(nBlockWidth, width);
nBlockHeight = MIN(nBlockHeight, height);
//得到每一塊的數據
unsigned char* pCDataSrc = pRDataSrc + nCI * block_size * 3;
unsigned int* pCDataDst = pRDataDst + nCI * block_size;
uchar* pCDataBound = pRDataBound + nCI * block_size;
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned char* pSubDataSrc = pCDataSrc + j * width * 3;
unsigned char* pSubBlockDataDst = pDataBlock[ti] + j * nBlockWidth * 3;
uchar* pSubDataBoundSrc = pCDataBound + j * width;
uchar* pSubDataBoundDst = pDataBound[ti] + j * nBlockWidth;
memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
memcpy(pSubDataBoundDst, pSubDataBoundSrc, nBlockWidth);
}
nCompCount[nBI] = ImgSegmentBlockMark(pDataBlock[ti], nBlockWidth, nBlockHeight, pDataBound[ti], pDataBlockDst[ti], -1, nLastIndex, sigma, k, min_size);
//將目標結果覆蓋到當前區域
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned int* pSubDataDst = pCDataDst + j * width;
unsigned int* pSubBlockDataDst = pDataBlockDst[ti] + j * nBlockWidth;
memcpy(pSubDataDst, pSubBlockDataDst, nBlockWidth * sizeof(int));
}
}
//根據分塊數目,更新索引,需要排除邊界
int nIndexOffset = 0;
//索引爲0的塊不用更新索引
for (int nBI = 1; nBI < nBISum; nBI++)
{
int nRI = nBI / nColIndex;
int nCI = nBI % nColIndex;
unsigned int* pRDataDst = pDataDst + nRI * block_size * width;
uchar* pRDataBound = pBound + nRI * block_size * width;
int nBlockWidth = block_size;
int nBlockHeight = block_size;
//行列末尾小塊處理
if (nCI == nColIndex - 1 && width % block_size != 0)nBlockWidth = (width) % block_size + block_size;
if (nRI == nRowIndex - 1 && height % block_size != 0)nBlockHeight = (height) % block_size + block_size;
//得到每一塊的數據
unsigned int* pCDataDst = pRDataDst + nCI * block_size;
uchar* pCDataBound = pRDataBound + nCI * block_size;
//累加偏移
nIndexOffset += nCompCount[nBI - 1];
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned int* pSubDataDst = pCDataDst + j * width;
uchar* pSubDataBoundSrc = pCDataBound + j * width;
for (int i = 0; i < nBlockWidth; ++i)
{
if (!pSubDataBoundSrc[i])
{
pSubDataDst[i] += nIndexOffset;
}
}
}
}
//必定大於0,加入判斷只是爲了防止意外崩潰
if (nBISum > 0)
{
nLastIndex = nIndexOffset + nCompCount[nBISum - 1];
}
for (int i = 0; i < nThreadNum; ++i)
{
delete[] pDataBlock[i];
delete[] pDataBlockDst[i];
delete[] pDataBound[i];
}
delete[] pDataBlock;
delete[] pDataBlockDst;
delete[] pDataBound;
delete[] nCompCount;
}
return nLastIndex;
}
int ImgSegBlock(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned char* pDataDst, int block_size, float sigma, float k, int min_size)
{
//block_size小於0則不分塊,sigma和k有內部處理
if (pDataSrc == nullptr || width <= 0 || height <= 0 || pDataDst == nullptr || min_size <= 0)
{
return -1;
}
//首先要找到整幅圖的邊界,創建對應的mask
IBufferX* pImage = new IBufferX(pDataSrc, width, height, 3);
CFindBoundary fb(pImage);
//如果nBgValue小於零,則不考慮背景
uchar* pBound = new uchar[width * height]();
if (nBgValue >= 0)
{
fb.Initialize(nBgValue == 0);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
PtInt ptCur(x, y);
pBound[y * width + x] = ptCur.IsInBoundInfoLine(fb.m_mBoundInfo[y]);
}
}
}
delete pImage;
int num = ImgSegmentBlock(pDataSrc, width, height, pBound, pDataDst, block_size, sigma, k, min_size);
delete[] pBound;
return num;
}
//如果區域橫款分塊,此時要特殊處理
bool IsAreaCrossVBound(AreaLines& area, int& x, int& y)
{
size_t nLineCount = area.size();
for (size_t i = 0; i < nLineCount; ++i)
{
CLineSeg sg = area[i];
if (sg.x_s == 0)
{
x = sg.x_s;
y = sg.y;
return true;
}
}
return false;
}
//如果區域豎跨分塊,此時需要特殊處理
bool IsAreaCrossHBound(AreaLines& area, int& x, int& y)
{
size_t nLineCount = area.size();
for (size_t i = 0; i < nLineCount; ++i)
{
CLineSeg sg = area[i];
if (sg.y == 0)
{
x = sg.x_s;
y = sg.y;
return true;
}
}
return false;
}
//注意返回的vetor的數量總比count多1,因爲索引是從1開始的,0爲邊界不處理
size_t TransAreas(unsigned int* buffer, unsigned char* bound, int width, int height, int count, std::vector<AreaLines*>& vAreas)
{
//分配空間
int nReal = count + 1;
vAreas = std::vector<AreaLines*>(nReal);
for (size_t i = 0; i < nReal; ++i)
{
vAreas[i] = new AreaLines();
}
for (size_t j = 0; j < height; ++j)
{
unsigned int* h_buffer = buffer + width * j;
unsigned char* h_bound = bound + width * j;
CLineSeg al(-1, -1, j);
//是否開啓新的線段
bool bStart = false;
//bool bEnd = true;
int cur_idx = -1;
for (size_t i = 0; i <= width; ++i)
{
if (i == width && bStart && cur_idx > 0)
{
vAreas[cur_idx]->push_back(al);
//bStart = false;
//bEnd = true;
continue;
}
if (h_bound[i])
{
if (bStart && cur_idx > 0)
{
vAreas[cur_idx]->push_back(al);
al.x_s = -1;
cur_idx = -1;
bStart = false;
}
}
else
{
int idx = h_buffer[i];
if (cur_idx != idx)
{
if (cur_idx != -1)
{
vAreas[cur_idx]->push_back(al);
}
al.x_s = i;
bStart = true;
//bEnd = false;
cur_idx = idx;
}
al.x_e = i;
}
}
}
return 0;
}
int FixBlockBorder(unsigned char* pDataSrc, int width, int height, uchar* pBound, unsigned int* pDataDst, int nLastIndex,
int block_size, float sigma, float k, int min_size)
{
if (block_size < 0)
{
return -1;
}
//==========================修復列方向的縫隙========================
int nColBorders = (width) / block_size - 1; //計算列方向上縫隙數
unsigned char* pNewBlock = new unsigned char[block_size * 3 * height * 3]();
unsigned char* pNewBound = new unsigned char[block_size * 3 * height]();
unsigned int* pNewDst = new unsigned int[block_size * 3 * height]();
//對每一個接縫進行處理,因爲可能存在很大的連通區域,所以必須整列處理
for (int nCBIdx = 0; nCBIdx < nColBorders; ++nCBIdx)
{
//得到每一塊的數據
unsigned char* pCDataSrc = pDataSrc + nCBIdx * block_size * 3;
unsigned int* pCDataDst = pDataDst + nCBIdx * block_size;
unsigned char* pCDataBound = pBound + nCBIdx * block_size;
//申請塊和相鄰塊的大小
int nBlockWidth = block_size * 2;
int nBlockHeight = height;
//行列末尾小塊處理
if (nCBIdx == nColBorders - 1 && width % block_size != 0)nBlockWidth = (width) % block_size + 2 * block_size;
//unsigned char* pNewBlock = new unsigned char[nBlockWidth * nBlockHeight * 3]();
//unsigned char* pNewBound = new unsigned char[nBlockWidth * nBlockHeight]();
//unsigned int* pNewDst = new unsigned int[nBlockWidth * nBlockHeight]();
memset(pNewBound, 0, nBlockWidth * nBlockHeight/* * sizeof(char)*/);
//對於每一個分塊的接縫處,需要提取相關的塊
std::map<int, int> miiV;
int x = block_size - 1; //豎線的x
//int y = block_size - 1; //橫線的y
for (size_t bl = 0; bl < nBlockHeight; ++bl)
{
if (!imData(pCDataBound, x, bl, width))
{
miiV.insert(std::make_pair(imData(pCDataDst, x, bl, width), bl));
}
if (!imData(pCDataBound, x + 1, bl, width))
{
miiV.insert(std::make_pair(imData(pCDataDst, x + 1, bl, width), bl));
}
}
//獲得原圖像
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned char* pSubDataSrc = pCDataSrc + h * width * 3;
unsigned char* pSubBlockDataDst = pNewBlock + h * nBlockWidth * 3;
memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
}
//獲得新的邊界
for (size_t h = 0; h < nBlockHeight; ++h)
{
uchar* pSubDataBoundSrc = pCDataBound + h * width;
unsigned int* pSubDataDst = pCDataDst + h * width;
uchar* pSubDataBoundDst = pNewBound + h * nBlockWidth;
for (size_t w = 0; w < nBlockWidth; ++w)
{
if (pSubDataBoundSrc[w] || miiV.find(pSubDataDst[w]) == miiV.end())
{
pSubDataBoundDst[w] = 1;
}
}
}
//SaveBufferPPM(pNewBlock, nBlockWidth, nBlockHeight);
//SaveBoundBufferPPM(pNewBound, nBlockWidth, nBlockHeight);
int num = ImgSegmentBlockMark(pNewBlock, nBlockWidth, nBlockHeight, pNewBound, pNewDst, -1, 0, sigma, k, min_size);
//SaveBufferPPM(pNewDst, nBlockWidth, nBlockHeight);
//轉換存儲結果,提高更新效率
std::vector<AreaLines*> vAreas;
TransAreas(pNewDst, pNewBound, nBlockWidth, nBlockHeight, num, vAreas);
#ifdef CHECK_TRANSRESULT
for (size_t j = 1; j < vAreas.size(); ++j)
{
AreaLines* alsl = vAreas[j];
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCData = pNewDst + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
if (pSubCData[u] != j)
{
int a = 0;
}
pSubCData[u] = j + 1;
}
}
}
SaveBufferPPM(pNewDst, nBlockWidth, nBlockHeight);
#endif // 0
#ifndef FIX_VERTICAL
//將目標結果覆蓋到當前區域
unsigned int* pDstTmp = new unsigned int[nBlockWidth * nBlockHeight];
//初始化爲原來的值
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned int* pSubDataDst = pCDataDst + h * width;
unsigned int* pSubDstTmp = pDstTmp + h * nBlockWidth;
memcpy(pSubDstTmp, pSubDataDst, nBlockWidth * sizeof(int));
}
//std::map<int, int> mib;
for (size_t bl = 0; bl < nBlockHeight; ++bl)
{
if (!imData(pCDataBound, x, bl, width))
{
int idxl = imData(pCDataDst, x, bl, width);
int idxl_new = imData(pNewDst, x, bl, nBlockWidth);
//將右側區域中的對應的區域替換成左邊的區域
if (vAreas[idxl_new]->size())
{
// if (mib.find(idxl) == mib.end())
// {
std::vector<CLineSeg>* alsl = vAreas[idxl_new];
int tmp_idx = idxl;
int cross_x = -1, cross_y = -1;
if (IsAreaCrossVBound(*alsl, cross_x, cross_y))
{
tmp_idx = imData(pCDataDst, cross_x, cross_y, width);
}
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCDataDst = pDstTmp + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCDataDst[u] = tmp_idx;
}
}
// mib.insert(std::make_pair(idxl, idxl_new));
// }
}
int idxr = imData(pCDataDst, x + 1, bl, width);
int idxr_new = imData(pNewDst, x + 1, bl, nBlockWidth);
//將右側區域中的對應的區域替換成左邊的區域
if (/*idxr == imData(pDstTmp, x + 1, bl, nBlockWidth) && */vAreas[idxr_new]->size())
{
// if (mib.find(idxr) == mib.end())
// {
std::vector<CLineSeg>* alsl = vAreas[idxr_new];
int tmp_idx = idxr;
int cross_x = -1, cross_y = -1;
if (IsAreaCrossVBound(*alsl, cross_x, cross_y))
{
tmp_idx = imData(pCDataDst, cross_x, cross_y, width);
}
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCDataDst = pDstTmp + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCDataDst[u] = tmp_idx;
}
}
// mib.insert(std::make_pair(idxr, idxr_new));
// }
}
}
}
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned int* pSubDataDst = pCDataDst + h * width;
unsigned int* pSubDstTmp = pDstTmp + h * nBlockWidth;
memcpy(pSubDataDst, pSubDstTmp, nBlockWidth * sizeof(int));
}
#endif // 0
#ifdef BLOCK_RESULT
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned int* pSubDataDst = pCDataDst + j * width;
unsigned int* pSubBlockDataDst = pNewDst + j * nBlockWidth;
memcpy(pSubDataDst, pSubBlockDataDst, nBlockWidth * sizeof(int));
}
#endif // 0
delete[] pDstTmp;
pDstTmp = nullptr;
for (std::vector<AreaLines*>::iterator it = vAreas.begin(); it != vAreas.end(); ++it)
{
if (*it)
{
delete *it;
*it = nullptr;
}
}
}
delete[] pNewBlock;
delete[] pNewBound;
delete[] pNewDst;
//==========================修復行方向的縫隙========================
int nRowBorders = (height) / block_size - 1; //計算行方向上縫隙數
pNewBlock = new unsigned char[block_size * 3 * width * 3]();
pNewBound = new unsigned char[block_size * 3 * width]();
pNewDst = new unsigned int[block_size * 3 * width]();
//對每一個接縫進行處理,因爲可能存在很大的連通區域,所以必須整行處理
//for (int nRBIdx = 0; nRBIdx < 3; ++nRBIdx)
for (int nRBIdx = 0; nRBIdx < nRowBorders; ++nRBIdx)
{
//得到每一塊的數據
unsigned char* pCDataSrc = pDataSrc + nRBIdx * block_size * width * 3;
unsigned int* pCDataDst = pDataDst + nRBIdx * block_size * width;
unsigned char* pCDataBound = pBound + nRBIdx * block_size * width;
//申請塊和相鄰塊的大小
int nBlockWidth = width;
int nBlockHeight = block_size * 2;
//行列末尾小塊處理
//if (nRBIdx == nColBorders - 1 && width % block_size != 0)nBlockWidth = (width) % block_size + 2 * block_size;
if (nRBIdx == nRowBorders - 1 && height % block_size != 0)nBlockHeight = (height) % block_size + 2 * block_size;
//unsigned char* pNewBlock = new unsigned char[nBlockWidth * nBlockHeight * 3]();
//unsigned char* pNewBound = new unsigned char[nBlockWidth * nBlockHeight]();
//unsigned int* pNewDst = new unsigned int[nBlockWidth * nBlockHeight]();
memset(pNewBound, 0, nBlockWidth * nBlockHeight/* * sizeof(char)*/);
//對於每一個分塊的接縫處,需要提取相關的塊
std::map<int, int> miiH;
int y = block_size - 1; //橫線的y
for (size_t bl = 0; bl < width; ++bl)
{
if (!imData(pCDataBound, bl, y, width))
{
miiH.insert(std::make_pair(imData(pCDataDst, bl, y, width), bl));
}
if (!imData(pCDataBound, bl, y + 1, width))
{
miiH.insert(std::make_pair(imData(pCDataDst, bl, y + 1, width), bl));
}
}
//獲得原圖像
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned char* pSubDataSrc = pCDataSrc + h * width * 3;
unsigned char* pSubBlockDataDst = pNewBlock + h * nBlockWidth * 3;
memcpy(pSubBlockDataDst, pSubDataSrc, nBlockWidth * 3);
}
//獲得新的邊界
for (size_t h = 0; h < nBlockHeight; ++h)
{
uchar* pSubDataBoundSrc = pCDataBound + h * width;
unsigned int* pSubDataDst = pCDataDst + h * width;
uchar* pSubDataBoundDst = pNewBound + h * nBlockWidth;
for (size_t w = 0; w < nBlockWidth; ++w)
{
if (pSubDataBoundSrc[w] || miiH.find(pSubDataDst[w]) == miiH.end())
{
pSubDataBoundDst[w] = 1;
}
}
}
//SaveBufferPPM(pNewBlock, nBlockWidth, nBlockHeight);
//SaveBoundBufferPPM(pNewBound, nBlockWidth, nBlockHeight);
int num = ImgSegmentBlockMark(pNewBlock, nBlockWidth, nBlockHeight, pNewBound, pNewDst, -1, 0, sigma, k, min_size);
//SaveBufferPPM(pNewDst, nBlockWidth, nBlockHeight);
//轉換存儲結果,提高更新效率
std::vector<AreaLines*> vAreas;
TransAreas(pNewDst, pNewBound, nBlockWidth, nBlockHeight, num, vAreas);
#ifdef CHECK_TRANSRESULT
for (size_t j = 1; j < vAreas.size(); ++j)
{
std::vector<CLineSeg>* alsl = vAreas[j];
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCData = pNewDst + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCData[u] = j + 1;
}
}
}
//SaveBufferPPM(pNewDst, nBlockWidth, nBlockHeight);
#endif // 0
#ifndef FIX_HORIZONTAL
unsigned int* pDstTmp = new unsigned int[nBlockWidth * nBlockHeight];
//初始化爲原來的值
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned int* pSubDataDst = pCDataDst + h * width;
unsigned int* pSubDstTmp = pDstTmp + h * nBlockWidth;
memcpy(pSubDstTmp, pSubDataDst, nBlockWidth * sizeof(int));
}
//_tstring stSaveOld = _T("D:\\pOldDst") + CStdTpl::ConvertToString(nRBIdx) +_T(".ppm");
//std::string sSaveOld = CStdStr::ws2s(stSaveOld);
//SaveBufferPPM(pDstTmp, nBlockWidth, nBlockHeight, sSaveOld.c_str());
//_tstring stSavePath = _T("D:\\pNewDst") + CStdTpl::ConvertToString(nRBIdx) +_T(".ppm");
//std::string sSavePath = CStdStr::ws2s(stSavePath);
//SaveBufferPPM(pNewDst, nBlockWidth, nBlockHeight, sSavePath.c_str());
//_tstring stAllPath = _T("D:\\all") + CStdTpl::ConvertToString(2 * nRBIdx) +_T(".ppm");
//std::string sAllPath = CStdStr::ws2s(stAllPath);
//SaveBufferPPM(pDataDst, width, height, sAllPath.c_str());
//std::map<int, int> mib;
for (size_t bl = 0; bl < nBlockWidth; ++bl)
{
if (!imData(pCDataBound, bl, y, width))
{
//讀取原來的值
int idxd = imData(pCDataDst, bl, y, width);
int idxd_new = imData(pNewDst, bl, y, nBlockWidth);
int idxu = imData(pCDataDst, bl, y + 1, width);
int idxu_new = imData(pNewDst, bl, y + 1, nBlockWidth);
//區域替換
if (/*idxd == imData(pDstTmp, bl, y, width) && */vAreas[idxd_new]->size())
{
// if (mib.find(idxd) == mib.end())
// {
std::vector<CLineSeg>* alsl = vAreas[idxd_new];
int tmp_idx = idxd;
int cross_x = -1, cross_y = -1;
if (IsAreaCrossHBound(*alsl, cross_x, cross_y))
{
tmp_idx = imData(pCDataDst, cross_x, cross_y, width);
}
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCDataDst = pDstTmp + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCDataDst[u] = tmp_idx;
}
}
// mib.insert(std::make_pair(idxd, idxd_new));
// }
}
if (/*idxu == imData(pDstTmp, bl, y + 1, nBlockWidth) && */vAreas[idxd_new]->size())
{
// if (mib.find(idxu) == mib.end())
// {
std::vector<CLineSeg>* alsl = vAreas[idxu_new];
int tmp_idx = idxu;
int cross_x = -1, cross_y = -1;
if (IsAreaCrossHBound(*alsl, cross_x, cross_y))
{
tmp_idx = imData(pCDataDst, cross_x, cross_y, width);
}
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCDataDst = pDstTmp + al.y * nBlockWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCDataDst[u] = tmp_idx;
}
}
// mib.insert(std::make_pair(idxu, idxu_new));
// }
}
}
}
for (size_t h = 0; h < nBlockHeight; ++h)
{
unsigned int* pSubDataDst = pCDataDst + h * width;
unsigned int* pSubDstTmp = pDstTmp + h * nBlockWidth;
memcpy(pSubDataDst, pSubDstTmp, nBlockWidth * sizeof(int));
}
//_tstring stAllPathAfter = _T("D:\\all") + CStdTpl::ConvertToString(2 * nRBIdx + 1) +_T(".ppm");
//std::string sAllPathAfter = CStdStr::ws2s(stAllPathAfter);
//SaveBufferPPM(pDataDst, width, height, sAllPathAfter.c_str());
#endif // 0
#ifdef BLOCK_RESULT
for (size_t j = 0; j < nBlockHeight; ++j)
{
unsigned int* pSubDataDst = pCDataDst + j * width;
unsigned int* pSubBlockDataDst = pNewDst + j * nBlockWidth;
memcpy(pSubDataDst, pSubBlockDataDst, nBlockWidth * sizeof(int));
}
#endif // 0
delete[] pDstTmp;
pDstTmp = nullptr;
for (std::vector<AreaLines*>::iterator it = vAreas.begin(); it != vAreas.end(); ++it)
{
if (*it)
{
delete *it;
*it = nullptr;
}
}
}
delete[] pNewBlock;
delete[] pNewBound;
delete[] pNewDst;
return 0;
}
int ImgSegBlockMark(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned int* pDataDst, int block_size, float sigma, float k, int min_size)
{
//block_size小於0則不分塊,sigma和k有內部處理
if (pDataSrc == nullptr || width <= 0 || height <= 0 || pDataDst == nullptr || min_size <= 0)
{
return -1;
}
//首先要找到整幅圖的邊界,創建對應的mask
IBufferX* pImage = new IBufferX(pDataSrc, width, height, 3);
CFindBoundary fb(pImage);
//如果nBgValue小於零,則不考慮背景
uchar* pBound = new uchar[width * height]();
if (nBgValue >= 0)
{
fb.Initialize(nBgValue == 0);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
PtInt ptCur(x, y);
pBound[y * width + x] = ptCur.IsInBoundInfoLine(fb.m_mBoundInfo[y]);
}
}
}
delete pImage;
//必須初始化爲0
int nLastIndex = 0;
nLastIndex = ImgSegmentBlockMark(pDataSrc, width, height, pBound, pDataDst, block_size, nLastIndex, sigma, k, min_size);
if (block_size > 0 && (width > block_size || height > block_size))
{
FixBlockBorder(pDataSrc, width, height, pBound, pDataDst, nLastIndex, block_size, sigma, k, min_size);
}
delete[] pBound;
return nLastIndex;
}
int KMeansSegment(unsigned char* pDataSrc, int width, int height, int nBgValue, unsigned int* pDataDst, int block_size, float sigma, float k, int min_size)
{
//block_size小於0則不分塊,sigma和k有內部處理
if (pDataSrc == nullptr || width <= 0 || height <= 0 || pDataDst == nullptr || min_size <= 0)
{
return -1;
}
//首先要找到整幅圖的邊界,創建對應的mask
IBufferX* pImage = new IBufferX(pDataSrc, width, height, 3);
CFindBoundary fb(pImage);
//如果nBgValue小於零,則不考慮背景
uchar* pBound = new uchar[width * height]();
if (nBgValue >= 0)
{
fb.Initialize(nBgValue == 0);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
PtInt ptCur(x, y);
pBound[y * width + x] = ptCur.IsInBoundInfoLine(fb.m_mBoundInfo[y]);
}
}
}
delete pImage;
//必須初始化爲0
int nLastIndex = 0;
nLastIndex = ImgSegmentBlockMark(pDataSrc, width, height, pBound, pDataDst, block_size, nLastIndex, sigma, k, min_size);
//if (block_size > 0 && (width > block_size || height > block_size))
//{
// FixBlockBorder(pDataSrc, width, height, pBound, pDataDst, nLastIndex, block_size, sigma, k, min_size);
//}
if (nLastIndex)
{
//根據kmeans對所得到的過於精細的分割進行聚類處理,參考因子爲每個小塊中rgb的均值
//轉換存儲結果,提高更新效率
std::vector<AreaLines*> vAreas;
TransAreas(pDataDst, pBound, width, height, nLastIndex, vAreas);
#ifdef CHECK_TRANSRESULT
for (size_t j = 1; j < vAreas.size(); ++j)
{
std::vector<CLineSeg>& alsl = vAreas[j]->vLines;
for (size_t l = 0; l < alsl.size(); ++l)
{
CLineSeg al = alsl[l];
unsigned int* pSubCData = pDataDst + al.y * width;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCData[u] = j + 1;
}
}
}
#endif // 0
int& nWidth = width;
int& nHeight = height;
int nBandNum = 3;
//對得到的每一個結果取得rgb的均值,作爲聚類的參考
int size = nLastIndex; //樣本個數,實際上可能比nLastIndex小
const int dim = nBandNum; //Dimension of feature
const int cluster_num = 5; //Cluster number
const size_t lMemSize = size * dim;
double* data = new double[lMemSize * sizeof(double)]();
int nKCount = 0;
for (int i = 1; i <= size; ++i)
{
//分別計算每個區域的rgb的均值,並且注意是rgb是連續在一起的
std::vector<CLineSeg>* alsl = vAreas[i];
long lrgbSum[3] = {0};
long lPixCount = 0;
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned char* pSubData = pDataSrc + al.y * width * 3;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
//需要找到原圖上對應的點,然後分別計算出rgb的和
for (size_t c = 0; c < 3; ++c)
{
lrgbSum[c] += pSubData[u * 3 + c];
}
++lPixCount;
}
}
if (lPixCount)
{
for (size_t c = 0; c < 3; ++c)
{
//i從1開始,整數相除
data[nKCount * 3 + c] = lrgbSum[c] / lPixCount;
}
++nKCount;
}
}
//實際數目
size = MIN(size, nKCount);
KMeans* kmeans = new KMeans(dim, cluster_num);
int* labels = new int[size];
kmeans->SetInitMode(KMeans::InitUniform);
kmeans->Cluster(data, size, labels);
for (int i = 0; i < size; ++i)
{
//printf("%f, %f, %f belongs to %d cluster\n", data[i*dim + 0], data[i*dim + 1], data[i*dim + 2], labels[i]);
std::vector<CLineSeg>* alsl = vAreas[i + 1];
for (size_t l = 0; l < alsl->size(); ++l)
{
CLineSeg al = (*alsl)[l];
unsigned int* pSubCData = pDataDst + al.y * nWidth;
for (size_t u = al.x_s; u <= al.x_e; ++u)
{
pSubCData[u] = labels[i] + 1; //labels是從0開始的
}
}
}
delete[] data;
delete[] labels;
delete kmeans;
//CStdTpl::DelPointerSafely(data, true);
//CStdTpl::DelPointerSafely(labels, true);
//CStdTpl::DelPointerSafely(kmeans);
for (std::vector<AreaLines*>::iterator it = vAreas.begin(); it != vAreas.end(); ++it)
{
if (*it)
{
delete *it;
*it = nullptr;
}
}
nLastIndex = cluster_num;
}
delete[] pBound;
return nLastIndex;
}
更多的交流,歡迎留言。