2012-01-30 232 views
0

我一直在试图得到一个简单的洪水填充算法,为我开发的iPhone应用程序工作,我只是无法让它正常工作。洪水填充崩溃

我已经得到了实际的工作过程,但是当填充过大时,应用程序会崩溃。从我可以告诉它,因为线程溢出所有运行的功能。从我读过的内容来看,我需要实现一个堆栈,但是我无法弄清楚它是如何工作的。

typedef struct { 
int red; 
int green; 
int blue; 
} color; 

@interface EMFloodTest : UIViewController { 

UIImageView *mainImage; 
unsigned char *imageData; 

color selColor; 
color newColor; 

int maxByte; 
} 

@end 


@implementation EMFloodTest 

- (void)setupImageData { 
CGImageRef imageRef = mainImage.image.CGImage; 
if (imageRef == NULL) { return; } 
NSUInteger width = CGImageGetWidth(imageRef); 
NSUInteger height = CGImageGetHeight(imageRef); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
NSUInteger bytesPerPixel = 4; 
NSUInteger bytesPerRow = bytesPerPixel * width; 
NSUInteger bitsPerComponent = 8; 

maxByte = height * width * 4; 
imageData = malloc(height * width * 4); 

CGContextRef context = CGBitmapContextCreate(imageData, width, height, bitsPerComponent, bytesPerRow, colorSpace, 
              kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
CGColorSpaceRelease(colorSpace); 
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 
CGContextRelease(context); 
} 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
if (self) { 
    mainImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"Color6.png"]]; 
    [self.view addSubview:mainImage]; 
    newColor.red = 255; 
    newColor.green = 94; 
    newColor.blue = 0; 
    [self setupImageData]; 
} 
return self; 
} 

- (void)updateImage { 
CGImageRef imageRef = mainImage.image.CGImage; 
if (imageRef == NULL) { return; } 
NSUInteger width = CGImageGetWidth(imageRef); 
NSUInteger height = CGImageGetHeight(imageRef); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
NSUInteger bytesPerPixel = 4; 
NSUInteger bytesPerRow = bytesPerPixel * width; 
NSUInteger bitsPerComponent = 8; 

CGContextRef context = CGBitmapContextCreate(imageData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); 

imageRef = CGBitmapContextCreateImage (context); 
mainImage.image = [UIImage imageWithCGImage:imageRef]; 

CGContextRelease(context); 
} 

- (void)setPixel:(NSUInteger)byte toColor:(color)color { 
imageData[byte] = color.red; 
imageData[byte+1] = color.green; 
imageData[byte+2] = color.blue; 
} 

- (BOOL)testByte:(NSInteger)byte againstColor:(color)color { 
if (imageData[byte] == color.red && imageData[byte+1] == color.green && imageData[byte+2] == color.blue) { 
    return YES; 
} else { 
    return NO; 
} 
} 

// This is where the flood fill starts. Its a basic implementation but crashes when filling large sections. 

- (void)floodFillFrom:(NSInteger)byte bytesPerRow:(NSInteger)bpr { 
int u = byte - bpr; 
int r = byte + 4; 
int d = byte + bpr; 
int l = byte - 4; 
if ([self testByte:u againstColor:selColor]) { 
    [self setPixel:u toColor:newColor]; 
    [self floodFillFrom:u bytesPerRow:bpr]; 
} 
if ([self testByte:r againstColor:selColor]) { 
    [self setPixel:r toColor:newColor]; 
    [self floodFillFrom:r bytesPerRow:bpr]; 
} 
if ([self testByte:d againstColor:selColor]) { 
    [self setPixel:d toColor:newColor]; 
    [self floodFillFrom:d bytesPerRow:bpr]; 
} 
if ([self testByte:l againstColor:selColor]) { 
    [self setPixel:l toColor:newColor]; 
    [self floodFillFrom:l bytesPerRow:bpr]; 
} 
} 

- (void)startFillFrom:(NSInteger)byte bytesPerRow:(NSInteger)bpr { 
if (imageData[byte] == 0 && imageData[byte+1] == 0 && imageData[byte+2] == 0) { 
    NSLog(@"Black Selected"); 
    return; 
} else if ([self testByte:byte againstColor:newColor]) { 
    NSLog(@"Same Fill Color"); 
} else { 
    // code goes here 
    NSLog(@"Color to be replaced"); 
    [self floodFrom:byte bytesPerRow:bpr]; 
    [self updateImage]; 
} 
} 


- (void)selectedColor:(CGPoint)point { 
CGImageRef imageRef = mainImage.image.CGImage; 
if (imageRef == NULL) { return; } 
if (imageData == NULL) { return; } 
NSInteger width = CGImageGetWidth(imageRef); 
NSInteger byteNumber = 4*((width*round(point.y))+round(point.x)); 
NSInteger bytesPerPixel = 4; 
NSInteger bytesPerRow = bytesPerPixel * width; 

selColor.red = imageData[byteNumber]; 
selColor.green = imageData[byteNumber + 1]; 
selColor.blue = imageData[byteNumber + 2]; 
NSLog(@"Selected Color, RGB: %i, %i, %i",selColor.red, selColor.green, selColor.blue); 
NSLog(@"Byte:%i",byteNumber); 
[self startFillFrom:byteNumber bytesPerRow:bytesPerRow]; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
UITouch *touch = [touches anyObject]; 
CGPoint location = [touch locationInView:mainImage]; 
[self selectedColor:location]; 
} 

任何帮助我如何能够实现一个堆栈甚至使用其他算法将不胜感激。

最佳, 达伦

+0

看看[这里](https://github.com/OgreSwamp/ObjFloodFill/blob/master/src/ FloodFill.m) – 2012-01-30 07:02:26

+0

谢谢Parag。我已经下载了代码b4并试图解决它。我甚至试图在其中复制堆栈函数,但它没有帮助。 – EcksMedia 2012-01-30 07:27:40

+0

你解决了这个问题,我有同样的问题,但我不知道它 – 2013-02-25 10:40:58

回答

0

问题是递归实现。

太深的递归调用函数会导致堆栈溢出错误。

你必须以迭代的方式实现你的算法。

如果你想看到洪水填充的迭代例如,您可以访问:
UIImageScanlineFloodfill