Files
documents-ocr-ios/Example/Pods/GPUImage/framework/Source/GPUImageHoughTransformLineDetector.m
2016-09-27 10:07:35 +03:00

242 lines
9.5 KiB
Objective-C

#import "GPUImageHoughTransformLineDetector.h"
@interface GPUImageHoughTransformLineDetector()
- (void)extractLineParametersFromImageAtFrameTime:(CMTime)frameTime;
@end
@implementation GPUImageHoughTransformLineDetector
@synthesize linesDetectedBlock;
@synthesize edgeThreshold;
@synthesize lineDetectionThreshold;
@synthesize intermediateImages = _intermediateImages;
- (id)init;
{
if (!(self = [super init]))
{
return nil;
}
// First pass: do edge detection and threshold that to just have white pixels for edges
// if ([GPUImageContext deviceSupportsFramebufferReads])
// if ([GPUImageContext deviceSupportsFramebufferReads])
// {
// thresholdEdgeDetectionFilter = [[GPUImageThresholdEdgeDetectionFilter alloc] init];
// thresholdEdgeDetectionFilter = [[GPUImageSobelEdgeDetectionFilter alloc] init];
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setThreshold:0.07];
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setEdgeStrength:0.25];
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setEdgeStrength:1.0];
// thresholdEdgeDetectionFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
// }
// else
// {
thresholdEdgeDetectionFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
// }
[self addFilter:thresholdEdgeDetectionFilter];
// Second pass: extract the white points and draw representative lines in parallel coordinate space
parallelCoordinateLineTransformFilter = [[GPUImageParallelCoordinateLineTransformFilter alloc] init];
[self addFilter:parallelCoordinateLineTransformFilter];
// Third pass: apply non-maximum suppression
if ([GPUImageContext deviceSupportsFramebufferReads])
{
nonMaximumSuppressionFilter = [[GPUImageThresholdedNonMaximumSuppressionFilter alloc] initWithPackedColorspace:YES];
}
else
{
nonMaximumSuppressionFilter = [[GPUImageThresholdedNonMaximumSuppressionFilter alloc] initWithPackedColorspace:NO];
}
[self addFilter:nonMaximumSuppressionFilter];
__unsafe_unretained GPUImageHoughTransformLineDetector *weakSelf = self;
#ifdef DEBUGLINEDETECTION
_intermediateImages = [[NSMutableArray alloc] init];
__unsafe_unretained NSMutableArray *weakIntermediateImages = _intermediateImages;
// __unsafe_unretained GPUImageOutput<GPUImageInput> *weakEdgeDetectionFilter = thresholdEdgeDetectionFilter;
// [thresholdEdgeDetectionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
// [weakIntermediateImages removeAllObjects];
// UIImage *intermediateImage = [weakEdgeDetectionFilter imageFromCurrentFramebuffer];
// [weakIntermediateImages addObject:intermediateImage];
// }];
//
// __unsafe_unretained GPUImageOutput<GPUImageInput> *weakParallelCoordinateLineTransformFilter = parallelCoordinateLineTransformFilter;
// [parallelCoordinateLineTransformFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
// UIImage *intermediateImage = [weakParallelCoordinateLineTransformFilter imageFromCurrentFramebuffer];
// [weakIntermediateImages addObject:intermediateImage];
// }];
__unsafe_unretained GPUImageOutput<GPUImageInput> *weakNonMaximumSuppressionFilter = nonMaximumSuppressionFilter;
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
UIImage *intermediateImage = [weakNonMaximumSuppressionFilter imageFromCurrentFramebuffer];
[weakIntermediateImages addObject:intermediateImage];
[weakSelf extractLineParametersFromImageAtFrameTime:frameTime];
}];
#else
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime) {
[weakSelf extractLineParametersFromImageAtFrameTime:frameTime];
}];
#endif
[thresholdEdgeDetectionFilter addTarget:parallelCoordinateLineTransformFilter];
[parallelCoordinateLineTransformFilter addTarget:nonMaximumSuppressionFilter];
self.initialFilters = [NSArray arrayWithObjects:thresholdEdgeDetectionFilter, nil];
// self.terminalFilter = colorPackingFilter;
self.terminalFilter = nonMaximumSuppressionFilter;
// self.edgeThreshold = 0.95;
self.lineDetectionThreshold = 0.12;
return self;
}
- (void)dealloc;
{
free(rawImagePixels);
free(linesArray);
}
#pragma mark -
#pragma mark Corner extraction
- (void)extractLineParametersFromImageAtFrameTime:(CMTime)frameTime;
{
// we need a normal color texture for this filter
NSAssert(self.outputTextureOptions.internalFormat == GL_RGBA, @"The output texture format for this filter must be GL_RGBA.");
NSAssert(self.outputTextureOptions.type == GL_UNSIGNED_BYTE, @"The type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
NSUInteger numberOfLines = 0;
CGSize imageSize = nonMaximumSuppressionFilter.outputFrameSize;
unsigned int imageByteSize = imageSize.width * imageSize.height * 4;
if (rawImagePixels == NULL)
{
rawImagePixels = (GLubyte *)malloc(imageByteSize);
linesArray = calloc(1024 * 2, sizeof(GLfloat));
}
glReadPixels(0, 0, (int)imageSize.width, (int)imageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
unsigned int imageWidth = imageSize.width * 4;
unsigned int currentByte = 0;
unsigned int cornerStorageIndex = 0;
unsigned long lineStrengthCounter = 0;
while (currentByte < imageByteSize)
{
GLubyte colorByte = rawImagePixels[currentByte];
// NSLog(@"(%d,%d): [%d,%d,%d,%d]", xCoordinate, yCoordinate, rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
// NSLog(@"[%d,%d,%d,%d]", rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
if (colorByte > 0)
{
unsigned int xCoordinate = currentByte % imageWidth;
unsigned int yCoordinate = currentByte / imageWidth;
lineStrengthCounter += colorByte;
// NSLog(@"(%d,%d): [%d,%d,%d,%d]", xCoordinate, yCoordinate, rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
CGFloat normalizedXCoordinate = -1.0 + 2.0 * (CGFloat)(xCoordinate / 4) / imageSize.width;
CGFloat normalizedYCoordinate = -1.0 + 2.0 * (CGFloat)(yCoordinate) / imageSize.height;
if (normalizedXCoordinate < 0.0)
{
// T space
// m = -1 - d/u
// b = d * v/u
if (normalizedXCoordinate > -0.05) // Test for the case right near the X axis, stamp the X intercept instead of the Y
{
linesArray[cornerStorageIndex++] = 100000.0;
linesArray[cornerStorageIndex++] = normalizedYCoordinate;
}
else
{
linesArray[cornerStorageIndex++] = -1.0 - 1.0 / normalizedXCoordinate;
linesArray[cornerStorageIndex++] = 1.0 * normalizedYCoordinate / normalizedXCoordinate;
}
}
else
{
// S space
// m = 1 - d/u
// b = d * v/u
if (normalizedXCoordinate < 0.05) // Test for the case right near the X axis, stamp the X intercept instead of the Y
{
linesArray[cornerStorageIndex++] = 100000.0;
linesArray[cornerStorageIndex++] = normalizedYCoordinate;
}
else
{
linesArray[cornerStorageIndex++] = 1.0 - 1.0 / normalizedXCoordinate;
linesArray[cornerStorageIndex++] = 1.0 * normalizedYCoordinate / normalizedXCoordinate;
}
}
numberOfLines++;
numberOfLines = MIN(numberOfLines, 1023);
cornerStorageIndex = MIN(cornerStorageIndex, 2040);
}
currentByte +=4;
}
// CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
// NSLog(@"Processing time : %f ms", 1000.0 * currentFrameTime);
if (linesDetectedBlock != NULL)
{
linesDetectedBlock(linesArray, numberOfLines, frameTime);
}
}
- (BOOL)wantsMonochromeInput;
{
// return YES;
return NO;
}
#pragma mark -
#pragma mark Accessors
//- (void)setEdgeThreshold:(CGFloat)newValue;
//{
// [(GPUImageCannyEdgeDetectionFilter *)thresholdEdgeDetectionFilter setThreshold:newValue];
//}
//
//- (CGFloat)edgeThreshold;
//{
// return [(GPUImageCannyEdgeDetectionFilter *)thresholdEdgeDetectionFilter threshold];
//}
- (void)setLineDetectionThreshold:(CGFloat)newValue;
{
nonMaximumSuppressionFilter.threshold = newValue;
}
- (CGFloat)lineDetectionThreshold;
{
return nonMaximumSuppressionFilter.threshold;
}
#ifdef DEBUGLINEDETECTION
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
// [thresholdEdgeDetectionFilter useNextFrameForImageCapture];
// [parallelCoordinateLineTransformFilter useNextFrameForImageCapture];
[nonMaximumSuppressionFilter useNextFrameForImageCapture];
[super newFrameReadyAtTime:frameTime atIndex:textureIndex];
}
#endif
@end