1// 2// PRTraceEdges.m 3// PRICE 4// 5// Created by Riccardo Mottola on Wed Jan 14 2004. 6// Copyright (c) 2004-2014 Carduus. All rights reserved. 7// 8// This application 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. 9// 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. 10 11 12#import "PRTraceEdges.h" 13#import "PRGrayscaleFilter.h" 14 15#include <math.h> 16#include <limits.h> 17 18 19@implementation PRTraceEdges 20 21- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel 22{ 23 int filterType; 24 BOOL useThreshold; 25 float thresLevel; 26 BOOL useZeroCross; 27 28 /* interpret the parameters */ 29 filterType = [[parameters objectAtIndex:0] intValue]; 30 useThreshold = [[parameters objectAtIndex:1] boolValue]; 31 thresLevel = [[parameters objectAtIndex:2] floatValue]; 32 useZeroCross = [[parameters objectAtIndex:3] boolValue]; 33 34 return [self edgeImage:image :filterType :useThreshold :thresLevel :useZeroCross]; 35} 36 37- (NSString *)actionName 38{ 39 return @"Trace Edges"; 40} 41 42 43- (PRImage *)edgeImage :(PRImage *)srcImage :(int)filterType :(BOOL)useThreshold :(float)thresholdLevel :(BOOL)useZeroCross 44{ 45 NSBitmapImageRep *srcImageRep; 46 PRImage *destImage; 47 NSBitmapImageRep *destImageRep; 48 NSInteger w, h; 49 NSInteger x, y; 50 NSInteger i, j; 51 unsigned char *srcData; 52 unsigned char *destData; 53 NSInteger destSamplesPerPixel; 54 register NSInteger srcBytesPerPixel; 55 register NSInteger destBytesPerPixel; 56 register NSInteger srcBytesPerRow; 57 register NSInteger destBytesPerRow; 58 float *M, *N; 59 unsigned char *p1; 60 int convMatrix[5][5]; 61 float convSum; 62 63 /* get source image representation and associated information */ 64 srcImageRep = [srcImage bitmapRep]; 65 66 w = [srcImageRep pixelsWide]; 67 h = [srcImageRep pixelsHigh]; 68 69 /* check bith depth and color/greyscale image */ 70 if ([srcImage hasColor]) 71 { 72 PRGrayscaleFilter *grayFilter; 73 74 grayFilter = [[PRGrayscaleFilter alloc] init]; 75 /* Luminance conversion leaves us more signal than average */ 76 srcImage = [grayFilter filterImage:srcImage :METHOD_LUMINANCE]; 77 [grayFilter release]; 78 srcImageRep = [srcImage bitmapRep]; 79 NSLog (@"done greyscale converting"); 80 } 81 82 srcBytesPerRow = [srcImageRep bytesPerRow]; 83 srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8; 84 destSamplesPerPixel = 1; 85 86 srcData = [srcImageRep bitmapData]; 87 88 89 /* allocate float data */ 90 M = (float *)calloc(h*w, sizeof(float)); 91 N = (float *)calloc(h*w, sizeof(float)); 92 93 /* copy the image to the float matrix */ 94 for (y = 0; y < h; y++) 95 { 96 p1 = srcData + y * srcBytesPerRow; 97 for (x = 0; x < w; x++) 98 { 99 100 M[y*w + x] = (double)p1[x*srcBytesPerPixel] / UCHAR_MAX; 101 } 102 } 103 104 105 /* set the filter matrix */ 106 for (i = 0; i < 5; i++) 107 for (j = 0; j < 5; j++) 108 convMatrix[i][j] = 0; 109 110 /* see PRCTraceEdge.h for the filter correspondences */ 111 switch (filterType) 112 { 113 case 1: NSLog(@"Pixel difference"); 114 convMatrix[1][1] = 0; 115 convMatrix[1][2] = -1; 116 convMatrix[1][3] = 0; 117 convMatrix[2][1] = 0; 118 convMatrix[2][2] = 2; 119 convMatrix[2][3] = -1; 120 break; 121 case 2: NSLog(@"Separated pixel difference"); 122 convMatrix[1][1] = 0; 123 convMatrix[1][2] = -1; 124 convMatrix[1][3] = 0; 125 convMatrix[2][1] = 1; 126 convMatrix[2][2] = 0; 127 convMatrix[2][3] = -1; 128 convMatrix[3][1] = 0; 129 convMatrix[3][2] = 1; 130 convMatrix[3][3] = 0; 131 break; 132 case 3: NSLog(@"Roberts"); 133 convMatrix[1][1] = -1; 134 convMatrix[1][2] = 0; 135 convMatrix[1][3] = -1; 136 convMatrix[2][1] = 0; 137 convMatrix[2][2] = 2; 138 convMatrix[2][3] = 0; 139 break; 140 case 4: NSLog(@"Prewitt"); 141 convMatrix[1][1] = 0; 142 convMatrix[1][2] = -1; 143 convMatrix[1][3] = -2; 144 convMatrix[2][1] = 1; 145 convMatrix[2][2] = 0; 146 convMatrix[2][3] = -1; 147 convMatrix[3][1] = 2; 148 convMatrix[3][2] = 1; 149 convMatrix[3][3] = 0; 150 break; 151 case 5: NSLog(@"Sobel"); 152 convMatrix[1][1] = 0; 153 convMatrix[1][2] = -2; 154 convMatrix[1][3] = -2; 155 convMatrix[2][1] = 2; 156 convMatrix[2][2] = 0; 157 convMatrix[2][3] = -2; 158 convMatrix[3][1] = 2; 159 convMatrix[3][2] = 2; 160 convMatrix[3][3] = 0; 161 break; 162 case 6: NSLog(@"Abdou x"); 163 convMatrix[0][0] = 1; 164 convMatrix[0][1] = 1; 165 convMatrix[0][2] = 0; 166 convMatrix[0][3] = -1; 167 convMatrix[0][4] = -1; 168 convMatrix[1][0] = 1; 169 convMatrix[1][1] = 2; 170 convMatrix[1][2] = 0; 171 convMatrix[1][3] = -2; 172 convMatrix[1][4] = -1; 173 convMatrix[2][0] = 1; 174 convMatrix[2][1] = 2; 175 convMatrix[2][2] = 0; 176 convMatrix[2][3] = -2; 177 convMatrix[2][4] = -1; 178 convMatrix[3][0] = 1; 179 convMatrix[3][1] = 2; 180 convMatrix[3][2] = 0; 181 convMatrix[3][3] = -2; 182 convMatrix[3][4] = -1; 183 convMatrix[4][0] = 1; 184 convMatrix[4][1] = 1; 185 convMatrix[4][2] = 0; 186 convMatrix[4][3] = -1; 187 convMatrix[4][4] = -1; 188 break; 189 case 7: NSLog(@"Laplacian 1"); 190 convMatrix[1][1] = 0; 191 convMatrix[1][2] = -1; 192 convMatrix[1][3] = 0; 193 convMatrix[2][1] = -1; 194 convMatrix[2][2] = 4; 195 convMatrix[2][3] = -1; 196 convMatrix[3][1] = 0; 197 convMatrix[3][2] = -1; 198 convMatrix[3][3] = 0; 199 break; 200 case 8: NSLog(@"Laplacian 2"); 201 convMatrix[1][1] = -1; 202 convMatrix[1][2] = 2; 203 convMatrix[1][3] = -1; 204 convMatrix[2][1] = 2; 205 convMatrix[2][2] = -4; 206 convMatrix[2][3] = 2; 207 convMatrix[3][1] = -1; 208 convMatrix[3][2] = 2; 209 convMatrix[3][3] = -1; 210 break; 211 case 9: NSLog(@"Laplacian Prewitt"); 212 convMatrix[1][1] = -1; 213 convMatrix[1][2] = -1; 214 convMatrix[1][3] = -1; 215 convMatrix[2][1] = -1; 216 convMatrix[2][2] = 8; 217 convMatrix[2][3] = -1; 218 convMatrix[3][1] = -1; 219 convMatrix[3][2] = -1; 220 convMatrix[3][3] = -1; 221 break; 222 default: 223 NSLog(@"Unknown filter type for Trace Edges."); 224 } 225 226 227 /* the core */ 228 for (y = 0 + 2; y < h - 3; y++) 229 for (x = 0 + 2; x < w - 3; x++) 230 { 231 convSum = 0; 232 for (i = -2; i <= 2; i++) 233 for (j = -2; j <= 2; j++) 234 convSum += convMatrix[i+2][j+2] * M[(y+i) * w + (x+j)]; 235 N[y*w + x] = convSum; 236 } 237 238 /* allocate destination image and its representation */ 239 destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)]; 240 destImageRep = [[NSBitmapImageRep alloc] 241 initWithBitmapDataPlanes:NULL 242 pixelsWide:w 243 pixelsHigh:h 244 bitsPerSample:8 245 samplesPerPixel:destSamplesPerPixel 246 hasAlpha:NO 247 isPlanar:NO 248 colorSpaceName:NSCalibratedWhiteColorSpace 249 bytesPerRow:0 250 bitsPerPixel:0]; 251 252 destData = [destImageRep bitmapData]; 253 destBytesPerRow = [destImageRep bytesPerRow]; 254 destBytesPerPixel = [destImageRep bitsPerPixel] / 8; 255 256 /* copy the image back from the float matrix */ 257 if (useThreshold) 258 { 259 if (useZeroCross) 260 { /* zero crossing */ 261 for (y = 0; y < h; y++) 262 { 263 p1 = destData + (y * destBytesPerRow); 264 for (x = 0; x < w; x++) 265 { 266 float temp; 267 temp = fabs(N[y*w + x]); 268 if (temp < thresholdLevel) 269 p1[x*destBytesPerPixel] = UCHAR_MAX; 270 else 271 p1[x*destBytesPerPixel] = 0; 272 } 273 } 274 } else 275 { /* no zero crossing */ 276 for (y = 0; y < h; y++) 277 { 278 p1 = destData + (y * destBytesPerRow); 279 for (x = 0; x < w; x++) 280 { 281 if (N[y*w + x] > thresholdLevel) 282 p1[x*destBytesPerPixel] = 0; 283 else 284 p1[x*destBytesPerPixel] = UCHAR_MAX; 285 } 286 } 287 } 288 } else 289 { /* thresholding to prevent clipping */ 290 for (y = 0; y < h; y++) 291 { 292 p1 = destData + (y * destBytesPerRow); 293 for (x = 0; x < w; x++) 294 { 295 float temp; 296 temp = fabs(N[y*w + x]); 297 if (temp < 0) 298 p1[x*destBytesPerPixel] = 0; 299 else if (temp < 1) 300 p1[x*destBytesPerPixel] = (unsigned char) rint(temp * UCHAR_MAX); 301 else 302 p1[x*destBytesPerPixel] = UCHAR_MAX; 303 } 304 } 305 } 306 307 /* let's free the float data */ 308 free(M); 309 free(N); 310 311 [destImage setBitmapRep:destImageRep]; 312 [destImageRep release]; 313 [destImage autorelease]; 314 return destImage; 315} 316 317@end 318