1// 2// PRCustTraceEdges.m 3// PRICE 4// 5// Created by Riccardo Mottola on Fri Mar 19 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#import "PRCustTraceEdges.h" 12#import "PRTraceEdges.h" 13#import "PRMedian.h" 14#import "PRGrayscaleFilter.h" 15#include <math.h> 16#include <limits.h> 17 18 19@implementation PRCustTraceEdges 20 21- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel 22{ 23 int filterType; 24 float thresLevel; 25 BOOL useZeroCross; 26 BOOL enable1; 27 enum medianForms form1; 28 int size1; 29 BOOL separable1; 30 BOOL enable2; 31 enum medianForms form2; 32 int size2; 33 BOOL separable2; 34 BOOL enable3; 35 enum medianForms form3; 36 int size3; 37 BOOL separable3; 38 39 40 /* interpret the parameters */ 41 filterType = [[parameters objectAtIndex:0] intValue]; 42 thresLevel = [[parameters objectAtIndex:1] floatValue]; 43 useZeroCross = [[parameters objectAtIndex:2] boolValue]; 44 enable1 = [[parameters objectAtIndex:3] boolValue]; 45 form1 = [[parameters objectAtIndex:4] intValue]; 46 size1 = [[parameters objectAtIndex:5] intValue]; 47 separable1 = [[parameters objectAtIndex:6] boolValue]; 48 enable2 = [[parameters objectAtIndex:7] boolValue]; 49 form2 = [[parameters objectAtIndex:8] intValue]; 50 size2 = [[parameters objectAtIndex:9] intValue]; 51 separable2 = [[parameters objectAtIndex:10] boolValue]; 52 enable3 = [[parameters objectAtIndex:11] boolValue]; 53 form3 = [[parameters objectAtIndex:12] intValue]; 54 size3 = [[parameters objectAtIndex:13] intValue]; 55 separable3 = [[parameters objectAtIndex:14] boolValue]; 56 57 return [self edgeImage 58 :image :filterType :thresLevel :useZeroCross 59 :enable1 :form1 :size1 :separable1 60 :enable2 :form2 :size2 :separable2 61 :enable3 :form3 :size3 :separable3 62 :progressPanel]; 63} 64 65- (NSString *)actionName 66{ 67 return @"Edge Tracer"; 68} 69 70 71- (PRImage *)edgeImage :(PRImage *)srcImage :(int)filterType :(float)thresholdLevel :(BOOL)useZeroCross :(BOOL)enable1 :(enum medianForms)form1 :(int)size1 :(BOOL)separable1 :(BOOL)enable2 :(enum medianForms)form2 :(int)size2 :(BOOL)separable2 :(BOOL) enable3 :(enum medianForms)form3 :(int)size3 :(BOOL)separable3 :(PRCProgress *)prPanel 72{ 73 PRImage *destImage; 74 NSBitmapImageRep *destImageRep; 75 unsigned char *destData; 76 NSInteger w, h; 77 NSInteger x, y; 78 NSInteger destSamplesPerPixel; 79 NSInteger destBytesPerRow; 80 NSInteger destBytesPerPixel; 81 PRMedian *medianFilter; 82 PRTraceEdges *edgeFilter; 83 int finalLevels; 84 int finalLevelSize; 85 86 progressSteps = 0; 87 totalProgressSteps = 1; 88 if (enable1) 89 totalProgressSteps += 2; 90 if (enable2) 91 totalProgressSteps += 2; 92 if (enable3) 93 totalProgressSteps += 2; 94 95 if (!enable1 && !enable2 && !enable3) /* if none of the median processors is enabled */ 96 totalProgressSteps++; 97 98 progPanel = prPanel; 99 100 /* check the number of images to process */ 101 finalLevels = 0; 102 if (enable1) 103 finalLevels++; 104 if (enable2) 105 finalLevels++; 106 if (enable3) 107 finalLevels++; 108 finalLevelSize = 0; 109 if (finalLevels) 110 finalLevelSize = UCHAR_MAX / finalLevels; 111 112 /* get source image representation and associated information */ 113 if (progPanel != nil) 114 { 115 [self setActivity:@"Get image size"]; 116 [self advanceProgress]; 117 } 118 119 w = [srcImage width]; 120 h = [srcImage height]; 121 122 /* check bith depth and color/greyscale image */ 123 if ([srcImage hasColor]) 124 { 125 PRGrayscaleFilter *grayFilter; 126 127 grayFilter = [[PRGrayscaleFilter alloc] init]; 128 srcImage = [grayFilter filterImage:srcImage :METHOD_LUMINANCE]; 129 [grayFilter release]; 130 } 131 destSamplesPerPixel = 1; 132 133 /* allocate destination image and its representation */ 134 destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)]; 135 destImageRep = [[NSBitmapImageRep alloc] 136 initWithBitmapDataPlanes:NULL 137 pixelsWide:w 138 pixelsHigh:h 139 bitsPerSample:8 140 samplesPerPixel:destSamplesPerPixel 141 hasAlpha:NO 142 isPlanar:NO 143 colorSpaceName:NSCalibratedWhiteColorSpace 144 bytesPerRow:0 145 bitsPerPixel:0]; 146 147 destData = [destImageRep bitmapData]; 148 destBytesPerRow = [destImageRep bytesPerRow]; 149 destBytesPerPixel = [destImageRep bitsPerPixel] / 8; 150 151 /* let's make the paper white */ 152 memset(destData, UCHAR_MAX, h * destBytesPerRow); 153 154 /* allocate filters */ 155 medianFilter = [[PRMedian alloc] init]; 156 edgeFilter = [[PRTraceEdges alloc] init]; 157 158 if (finalLevels > 0) 159 { 160 if (enable1) 161 { 162 PRImage *firstImage; 163 NSBitmapImageRep *firstImageRep; 164 NSInteger fiBytesPerRow; 165 NSInteger fiBytesPerPixel; 166 unsigned char *fiData; 167 168 if (progPanel != nil) 169 { 170 [self setActivity:@"Processing image 1: median"]; 171 [self advanceProgress]; 172 } 173 firstImage = [medianFilter medianImage :srcImage :form1 :size1 :separable1 :NULL]; 174 if (progPanel != nil) 175 { 176 [self setActivity:@"Processing image 1: trace edges"]; 177 [self advanceProgress]; 178 } 179 firstImage = [edgeFilter edgeImage :firstImage :filterType :YES :thresholdLevel :useZeroCross]; 180 firstImageRep = [firstImage bitmapRep]; 181 fiBytesPerRow = [firstImageRep bytesPerRow]; 182 fiBytesPerPixel = [firstImageRep bitsPerPixel] / 8; 183 fiData = [firstImageRep bitmapData]; 184 for (y = 0; y < h; y++) 185 { 186 for (x = 0; x < w; x++) 187 { 188 if (*(fiData + fiBytesPerRow*y + fiBytesPerPixel*x) == 0) 189 *(destData + destBytesPerRow*y + destBytesPerPixel*x) -= finalLevelSize; 190 } 191 } 192 } 193 194 if (enable2) 195 { 196 PRImage *secondImage; 197 NSBitmapImageRep *secondImageRep; 198 NSInteger siBytesPerRow; 199 NSInteger siBytesPerPixel; 200 unsigned char *siData; 201 202 if (progPanel != nil) 203 { 204 [self setActivity:@"Processing image 2: median"]; 205 [self advanceProgress]; 206 } 207 secondImage = [medianFilter medianImage :srcImage :form2 :size2 :separable2 :NULL]; 208 if (progPanel != nil) 209 { 210 [self setActivity:@"Processing image 2: trace edges"]; 211 [self advanceProgress]; 212 } 213 secondImage = [edgeFilter edgeImage :secondImage :filterType :YES :thresholdLevel :useZeroCross]; 214 secondImageRep = [secondImage bitmapRep]; 215 siBytesPerRow = [secondImageRep bytesPerRow]; 216 siBytesPerPixel = [secondImageRep bitsPerPixel] / 8; 217 siData = [secondImageRep bitmapData]; 218 for (y = 0; y < h; y++) 219 { 220 for (x = 0; x < w; x++) 221 { 222 if (*(siData + siBytesPerRow*y + siBytesPerPixel*x) == 0) 223 *(destData + destBytesPerRow*y + destBytesPerPixel*x) -= finalLevelSize; 224 } 225 } 226 } 227 228 if (enable3) 229 { 230 PRImage *thirdImage; 231 NSBitmapImageRep *thirdImageRep; 232 NSInteger tiBytesPerRow; 233 NSInteger tiBytesPerPixel; 234 unsigned char *tiData; 235 236 if (progPanel != nil) 237 { 238 [self setActivity:@"Processing image 3: median"]; 239 [self advanceProgress]; 240 } 241 thirdImage = [medianFilter medianImage :srcImage :form3 :size3 :separable3 :NULL]; 242 if (progPanel != nil) 243 { 244 [self setActivity:@"Processing image 3: trace edges"]; 245 [self advanceProgress]; 246 } 247 thirdImage = [edgeFilter edgeImage :thirdImage :filterType :YES :thresholdLevel :useZeroCross]; 248 thirdImageRep = [thirdImage bitmapRep]; 249 tiBytesPerRow = [thirdImageRep bytesPerRow]; 250 tiBytesPerPixel = [thirdImageRep bitsPerPixel] / 8; 251 tiData = [thirdImageRep bitmapData]; 252 for (y = 0; y < h; y++) 253 { 254 for (x = 0; x < w; x++) 255 { 256 if (*(tiData + tiBytesPerRow*y + tiBytesPerPixel*x) == 0) 257 *(destData + destBytesPerRow*y + destBytesPerPixel*x) -= finalLevelSize; 258 } 259 } 260 } 261 } 262 else 263 { 264 NSBitmapImageRep *srcImageRep; 265 unsigned char *srcData; 266 NSInteger srcBytesPerRow; 267 NSInteger srcBytesPerPixel; 268 269 /* no median processing */ 270 /* we conventionally process the image */ 271 if (progPanel != nil) 272 { 273 [self setActivity:@"Processing image: trace edges"]; 274 [self advanceProgress]; 275 } 276 srcImage = [edgeFilter edgeImage :srcImage :filterType :YES :thresholdLevel :useZeroCross]; 277 srcImageRep = [srcImage bitmapRep]; 278 srcBytesPerRow = [srcImageRep bytesPerRow]; 279 srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8; 280 srcData = [srcImageRep bitmapData]; 281 for (y = 0; y < h; y++) 282 { 283 for (x = 0; x < w; x++) 284 { 285 if (*(srcData + srcBytesPerRow*y + srcBytesPerPixel*x) == 0) 286 *(destData + destBytesPerRow*y + destBytesPerPixel*x) = 0; 287 } 288 } 289 } 290 291 /* release filters */ 292 [medianFilter release]; 293 [edgeFilter release]; 294 295 if (progPanel != nil) 296 { 297 [self setActivity:@"Done"]; 298 [self showProgress]; 299 } 300 301 [destImage setBitmapRep:destImageRep]; 302 [destImageRep release]; 303 [destImage autorelease]; 304 return destImage; 305} 306 307@end 308