import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.imageio.ImageIO;
/**
*分水岭算法进行图像分割
*@author zhshl
*@date 2014-10-31
*/
public class WaterShed {
private BufferedImage sourceImg;///原图
private BufferedImage gradImage;////灰度图
/**
* ///此处采用数组实现指向父节点的多叉树,根节点的父节点是它自己(指向自己,下标用转化后的数值表示比如i行j列,下标为:i*width+j)
* ///用查集数据结构来进行区域标记,主要目的在于简化区域块的合并
* ////记录分块数据
*/
private int [][] blockData;
private int width;
private int height;
private final int THRESHOD=25;
private int maxGrad;////最大梯度值,也是灌水灌到的最高点
private int RIDGE=-100;////该标志表示山脊
////保存图像对应区域的 块整体信息,key对应分块标记值
private HashMap<Integer,Img_Area_Feature> nodes=new HashMap<>();
/**
* 开始进行分水岭算法分割图片
* @param file
*/
public void startWatering(File file){
////初始化,包括滤波以及种子区域标记
init(file);
////开始进行分水岭算法
startWatering();
////获取分割结果的邻接图
getAdjacencyGraph();
///区域合并
areaCombine();
}
/**
* 开始灌水生长
*/
private void startWatering(){
for(int altitude=THRESHOD;altitude<=maxGrad;altitude++){
////外层循环,表示每次灌水达到的高度
int addedPixes=0;////记录每次循环有多少个像素点加入了集水盆,
do{
addedPixes=0;
////在某个高度下,一直循环到没有新像素点加入到集水盆为止
for(int j=0;j<height;j++){
for(int i=0;i<width;i++){
///内部循环遍历图片
int grad=(gradImage.getRGB(i, j)>>16)&0xFF;
if((grad<=altitude)&&(blockData[j][i]==-1)){
////处理未标记的区域
int num=0;///记录四领域集水盆数目
int parentIndex=-1;
////左边
if(i>0){////不超出边界
int value=blockData[j][i-1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
parentIndex=left_parentIndex;
num++;
}
}
////右边
if(i<width-1){////不超出边界
int value=blockData[j][i+1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////上边
if(j>0){////不超出边界
int value=blockData[j-1][i];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////下边
if(j<height-1){////不超出边界
int value=blockData[j+1][i];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
////当该标记点所在区域的值与之前的区域值不一致时,四邻域集水盆数目加一
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////左上
if(i>0&&j>0){////不超出边界
int value=blockData[j-1][i-1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////右上
if(i<width-1&&j>0){////不超出边界
int value=blockData[j-1][i+1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////左下
if(i>0&&j<height-1){////不超出边界
int value=blockData[j+1][i-1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表示行
left_i=left_parentIndex%width;///余数表示列
}
if(left_parentIndex!=parentIndex){
num++;
}
///把该集水盆的代表节点的父节点下标值记录下来
parentIndex=left_parentIndex;
}
}
////右下
if(i<width-1&&j<height-1){////不超出边界
int value=blockData[j+1][i+1];
if(value!=-1&&value!=-100){
///找到左边区域的根节点即某节点指向自身
int left_parentIndex=value;
int left_j=left_parentIndex/width;///商表示行
int left_i=left_parentIndex%width;///余数表示列
while(blockData[left_j][left_i]!=left_parentIndex){
left_parentIndex=blockData[left_j][left_i];
left_j=left_parentIndex/width;///商表�
- 1
- 2
前往页