问题描述
|
我正在尝试编写一些代码来浏览图像文件中的相同颜色的像素组。
我这样做的方法是逐像素遍历图像(以具有颜色的哈希码的1d整数数组的形式),以查找要搜索的颜色的像素。找到一个像素后,我会执行dfs来查找相同颜色的相邻像素,并将其添加到一个称为Blob的新对象中。我使用布尔数组来跟踪已经添加了哪些像素,因此我不会添加相同的斑点。
我为每个Blob对象使用ArrayList来跟踪像素数。然后,我使用另一个Blob的ArrayList来存储不同的组。
当我尝试在一个简单的示例(具有上半部白色和下半部底部的图片)上运行时,当尝试使用太大的图片时出现堆栈溢出错误。具体来说,当我尝试使用320x240的图像执行此操作时,将2752像素添加到Blob后,就会出现stackoverflow。
我只是在为自己想做的事情使用正确的数据结构吗?我读到ArrayLists可以在其中存储Integer.maxValue对象。
我的代码粘贴在下面。任何帮助是极大的赞赏。
//blobfind tests code to find similar pixels of a minimum size and groups them together for analysis later
//purpose is to identify color coded objects through the webcam
//util for ArrayList
import java.util.*;
import java.awt.Color;
import java.io.*;
public class Blobfind2 {
//width and height of image in pixels
private int width;
private int height;
//hash code for the color being searched for
private int colorCode;
//minimum blob size to be added
private int minPixels;
//image in form of array of hashcodes for each pixel
private int[] img;
//keeping track of which pixels have been added to a blob
private boolean[] added;
//keeping track of which pixels have been visited when looking for a new blob
private boolean[] visited;
//debugging variable
private int count;
public Blobfind2(int inwidth,int inheight,int inCCode,int inminPixels,int[] inimage) {
width = inwidth;
height = inheight;
colorCode = inCCode;
minPixels = inminPixels;
img = inimage;
count = 0;
}
//takes hashCodeof color,minimum pixel number,and an image in the form of integer array
public ArrayList findColor() {
//makes an arraylist of \"blobs\"
ArrayList bloblist = new ArrayList();
//keep track of which pixels have been added to a blob
boolean[] added = new boolean[width * height];
//checks through each pixel
for (int i = 0; i < img.length; i++) {
//if it matches and is not part of a blob,we run dfs to collect all the pixels in that blob
if ((img[i] == colorCode) && (added[i] == false)) {
//visited keeps track of which pixels in the blob have been visited
//refreshed each time a new blob is made
boolean[] visited = new boolean[width*height];
Blob currBlob = new Blob();
dfs(img,currBlob,i,Color.white.hashCode(),added,visited);
//adds the blob to the bloblist if it is of a certain size
if (currBlob.mass() >= minPixels) {
bloblist.add(currBlob);
}
}
}
return bloblist;
}
//recursive algorithm to find other members of a blob
public void dfs (int[] img,Blob blob,int currPixel,int colorCode,boolean[] added,boolean[] visited) {
//System.out.print(currPixel + \" - \" + count + \" \");
count++;
//check current pixel,this only happens on the first pixel
if (visited[currPixel] == false) {
blob.add(img[currPixel]);
added[currPixel] = true;
visited[currPixel] = true;
}
//checks down pixel
if ((currPixel + width < height*width) && (visited[currPixel + width] == false)) {
if (img[currPixel + width] == colorCode) {
blob.add(img[currPixel + width]);
currPixel = currPixel + width;
added[currPixel] = true;
visited[currPixel] = true;
dfs(img,blob,currPixel,colorCode,visited);
}
}
//checks up pixel
if ((currPixel - width > 0) && (visited[currPixel - width] == false)) {
if (img[currPixel - width] == colorCode) {
blob.add(img[currPixel - width]);
currPixel = currPixel - width;
added[currPixel] = true;
visited[currPixel] = true;
dfs (img,visited);
}
}
//checks right pixel
if ((currPixel + 1 < width * height) && (visited[currPixel + 1] == false) && (((currPixel + 1) % width) != 0)) {
if (img[currPixel + 1] == colorCode) {
blob.add(img[currPixel + 1]);
currPixel = currPixel + 1;
added[currPixel] = true;
visited[currPixel] = true;
dfs(img,visited);
}
}
//checks left pixel
if ((currPixel - 1 > 0) && (visited[currPixel - 1] == false) && (((currPixel - 1) % width) != width - 1)) {
if (img[currPixel - 1] == colorCode) {
blob.add(img[currPixel - 1]);
currPixel = currPixel - 1;
added[currPixel] = true;
visited[currPixel] = true;
dfs(img,visited);
}
}
return;
}
//test case,makes a new image thats half black and half white
//should only return one blob of size width*height/2
public static void main(String[] args) {
int width = 320;
int height = 240;
//builds the image
int[] img = new int[width * height];
for (int i = 0; i < img.length; i++) {
if (i < img.length/4) {
img[i] = Color.white.hashCode();
} else {
img[i] = Color.black.hashCode();
}
}
//runs blobfind
Blobfind2 bf = new Blobfind2(width,height,1,img);
ArrayList bloblist = bf.findColor();
System.out.println(bloblist.size());
//need to typecast things coming out of arraylists
Blob firstblob = (Blob)bloblist.get(0);
System.out.println(firstblob.mass());
}
private class Blob {
private ArrayList pixels = new ArrayList();
private Blob() {
}
private int mass() {
return pixels.size();
}
private void add(int i) {
pixels.add(i);
}
private ArrayList getBlob() {
return pixels;
}
}
}
解决方法
堆栈溢出错误与是否使用
List
或Map
或任何其他特定数据结构无关。这些构造在堆上分配。您正在看到堆栈溢出错误,因为您进行了递归函数调用。每个递归函数调用都会在堆栈上分配内存。您可以增加-Xss值(e.g java -Xss8m HelloWorld)
,也可以将算法重写为非递归算法(假设算法正确)。
,这看起来非常类似于泛洪算法。递归实现可能会使大型Blob崩溃(例如进行过多的递归调用),仅因为您必须为每个像素探索4个邻居。最坏的情况是图像全部在同一斑点中!
我会尝试使堆栈明确。您要避免递归,而应使用基于循环的简单方法。
public void dfs () {
Stack<Pixel> pixels = new Stack<Pixel>();
pixels.push(currentPixel);
while (!pixels.isEmpty()) {
Pixel x = pixels.pop();
// Do whatever processing on this pixel
Pixel upPixel = getUpPixel();
if (upPixel == colorCode) {
pixels.push(upPixel);
}
// And so on
}
}