1// 2// PRMedian.m 3// PRICE 4// 5// Created by Riccardo Mottola on Thu Mar 25 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 "PRMedian.h" 12#import "PRGrayscaleFilter.h" 13 14 15@implementation PRMedian 16 17- (PRImage *)filterImage:(PRImage *)image with:(NSArray *)parameters progressPanel:(PRCProgress *)progressPanel 18{ 19 enum medianForms form; 20 int size; 21 BOOL separable; 22 23 /* interpret the parameters */ 24 form = [[parameters objectAtIndex:0] intValue]; 25 size = [[parameters objectAtIndex:1] intValue]; 26 separable = [[parameters objectAtIndex:2] boolValue]; 27 28 return [self medianImage:image :form :size :separable :progressPanel]; 29} 30 31- (NSString *)actionName 32{ 33 return @"Median"; 34} 35 36 37- (PRImage *)medianImage :(PRImage *)srcImage :(enum medianForms)form :(int)size :(BOOL)separable :(PRCProgress *)prPanel 38{ 39 NSBitmapImageRep *srcImageRep; 40 PRImage *destImage; 41 NSBitmapImageRep *destImageRep; 42 NSInteger w, h; 43 NSInteger x, y; 44 NSInteger i, j; 45 unsigned char *srcData; 46 unsigned char *destData; 47 unsigned char *filterMask; /* the median window */ 48 int realSize; /* real width of the median window */ 49 int c; /* current channel */ 50 NSInteger srcSamplesPerPixel; 51 NSInteger destSamplesPerPixel; 52 register NSInteger srcBytesPerPixel; 53 register NSInteger destBytesPerPixel; 54 register NSInteger srcBytesPerRow; 55 register NSInteger destBytesPerRow; 56 57 progressSteps = 0; 58 totalProgressSteps = 2; 59 progPanel = prPanel; 60 61 realSize = size*2 + 1; 62 63 /* get source image representation and associated information */ 64 if (progPanel != nil) 65 { 66 [self setActivity:@"Get image size"]; 67 [self advanceProgress]; 68 } 69 srcImageRep = [srcImage bitmapRep]; 70 71 w = [srcImageRep pixelsWide]; 72 h = [srcImageRep pixelsHigh]; 73 srcBytesPerRow = [srcImageRep bytesPerRow]; 74 srcSamplesPerPixel = [srcImageRep samplesPerPixel]; 75 destSamplesPerPixel = srcSamplesPerPixel; 76 srcBytesPerPixel = [srcImageRep bitsPerPixel] / 8; 77 78 /* allocate destination image and its representation */ 79 destImage = [[PRImage alloc] initWithSize:NSMakeSize(w, h)]; 80 destImageRep = [[NSBitmapImageRep alloc] 81 initWithBitmapDataPlanes:NULL 82 pixelsWide:w 83 pixelsHigh:h 84 bitsPerSample:[srcImageRep bitsPerSample] 85 samplesPerPixel:destSamplesPerPixel 86 hasAlpha:[srcImage hasAlpha] 87 isPlanar:NO 88 colorSpaceName:[srcImageRep colorSpaceName] 89 bytesPerRow:w*destSamplesPerPixel 90 bitsPerPixel:0]; 91 srcData = [srcImageRep bitmapData]; 92 destData = [destImageRep bitmapData]; 93 destBytesPerRow = [destImageRep bytesPerRow]; 94 destBytesPerPixel = [destImageRep bitsPerPixel] / 8; 95 96 if (progPanel != nil) 97 { 98 [self setActivity:@"Filter"]; 99 [self advanceProgress]; 100 } 101 102 if (form == HORIZONTAL_F) 103 { 104 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (realSize)); 105 if (filterMask == NULL) 106 NSLog(@"Failed filterMask allocation in PRMedian"); 107 for (y = 0; y < h; y++) 108 { 109 for (x = 0 + size + 1; x < w - (size + 1); x++) 110 { 111 for (c = 0; c < destSamplesPerPixel; c++) 112 { 113 for (i = 0; i < realSize; i++) 114 filterMask[i] = srcData[srcBytesPerRow*y + (x - size + i)*srcBytesPerPixel + c]; 115 /* primitve sorting */ 116 for (i = 0; i < realSize-1; i++) 117 { 118 for (j = 0; j < realSize-1-i; j++) 119 { 120 if (filterMask[j] > filterMask[j+1]) 121 { 122 unsigned char temp; 123 temp = filterMask[j+1]; 124 filterMask[j+1] = filterMask[j]; 125 filterMask[j] = temp; 126 } 127 } 128 } 129 /* insert result in destination */ 130 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = filterMask[size]; 131 } 132 } 133 } 134 free(filterMask); 135 } else if (form == VERTICAL_F) 136 { 137 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (realSize)); 138 for (x = 0; x < w; x++) 139 { 140 for (y = 0 + size + 1; y < h - (size + 1); y++) 141 { 142 for (c = 0; c < destSamplesPerPixel; c++) 143 { 144 for (i = 0; i < realSize; i++) 145 filterMask[i] = srcData[(y - size + i) * srcBytesPerRow + x*srcBytesPerPixel + c]; 146 /* primitve sorting */ 147 for (i = 0; i < realSize-1; i++) 148 { 149 for (j = 0; j < realSize-1-i; j++) 150 { 151 if (filterMask[j] > filterMask[j+1]) 152 { 153 unsigned char temp; 154 temp = filterMask[j+1]; 155 filterMask[j+1] = filterMask[j]; 156 filterMask[j] = temp; 157 } 158 } 159 } 160 /* insert result in destination */ 161 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = filterMask[size]; 162 } 163 } 164 } 165 free(filterMask); 166 } else if (form == CROSS_F) 167 { 168 if (separable) 169 { 170 unsigned char tempResult; /* to store the result between the separable passes */ 171 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (realSize)); 172 for (x = 0 + size + 1; x < w - (size + 1); x++) 173 { 174 for (y = 0 + size + 1; y < h - (size + 1); y++) 175 { 176 for (c = 0; c < destSamplesPerPixel; c++) 177 { 178 for (i = 0; i < realSize; i++) 179 filterMask[i] = srcData[y*srcBytesPerRow + (x - size + i)*srcBytesPerPixel + c]; 180 181 /* primitve sorting */ 182 for (i = 0; i < realSize-1; i++) 183 { 184 for (j = 0; j < realSize-1-i; j++) 185 { 186 if (filterMask[j] > filterMask[j+1]) 187 { 188 unsigned char temp; 189 temp = filterMask[j+1]; 190 filterMask[j+1] = filterMask[j]; 191 filterMask[j] = temp; 192 } 193 } 194 } 195 tempResult = filterMask[size]; 196 for (i = 0; i < realSize; i++) 197 filterMask[i] = srcData[(y - size + i) * srcBytesPerRow + x*srcBytesPerPixel + c]; 198 filterMask[size] = tempResult; 199 /* primitve sorting */ 200 for (i = 0; i < realSize-1; i++) 201 { 202 for (j = 0; j < realSize-1-i; j++) 203 { 204 if (filterMask[j] > filterMask[j+1]) 205 { 206 unsigned char temp; 207 temp = filterMask[j+1]; 208 filterMask[j+1] = filterMask[j]; 209 filterMask[j] = temp; 210 } 211 } 212 } 213 /* insert result in destination */ 214 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = filterMask[size]; 215 } 216 } 217 } 218 free(filterMask); 219 } else /* not separable */ 220 { 221 int totalSize; /* the total number of samples in the filter */ 222 int k; 223 224 totalSize = 4 * size + 1; 225 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (totalSize)); 226 for (y = 0 + size + 1; y < h - (size + 1); y++) 227 { 228 for (x = 0 + size + 1; x < w - (size + 1); x++) 229 { 230 for (c = 0; c < destSamplesPerPixel; c++) 231 { 232 k = 0; 233 for (i = 0; i < realSize; i++) 234 filterMask[k++] = srcData[y * srcBytesPerRow + (x - size + i)*srcBytesPerPixel + c]; 235 for (i = 1; i <= size; i++) 236 filterMask[k++] = srcData[(y - i) * srcBytesPerRow + x*srcBytesPerPixel + c]; 237 for (i = 1; i <= size; i++) 238 filterMask[k++] = srcData[(y + i) * srcBytesPerRow + x*srcBytesPerPixel + c]; 239 240 241 /* primitve sorting */ 242 for (i = 0; i < totalSize-1; i++) 243 { 244 for (j = 0; j < totalSize-1-i; j++) 245 { 246 if (filterMask[j] > filterMask[j+1]) 247 { 248 unsigned char temp; 249 temp = filterMask[j+1]; 250 filterMask[j+1] = filterMask[j]; 251 filterMask[j] = temp; 252 } 253 } 254 } 255 /* insert result in destination */ 256 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = filterMask[2*size]; 257 } 258 } 259 } 260 free(filterMask); 261 } 262 } else if (form == BOX_F) 263 { 264 if (separable) 265 { 266 int k; 267 unsigned char *tempResult; 268 269 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (realSize)); 270 tempResult = (unsigned char *) malloc(sizeof(unsigned char) * (realSize)); 271 for (y = 0 + size + 1; y < h - (size + 1); y++) 272 { 273 for (x = 0 + size + 1; x < w - (size + 1); x++) 274 { 275 for (c = 0; c < destSamplesPerPixel; c++) 276 { 277 for (i = 0; i < realSize; i++) 278 { 279 for (j = 0; j < realSize; j++) 280 filterMask[j] = srcData[(y - size + i) * srcBytesPerRow + (x - size + j)*srcBytesPerPixel + c]; 281 282 /* primitve sorting */ 283 for (j = 0; j < realSize-1; j++) 284 { 285 for (k = 0; k < realSize-1-j; k++) 286 { 287 if (filterMask[k] > filterMask[k+1]) 288 { 289 unsigned char temp; 290 temp = filterMask[k+1]; 291 filterMask[k+1] = filterMask[k]; 292 filterMask[k] = temp; 293 } 294 } 295 } 296 /* insert result in destination */ 297 tempResult[i] = filterMask[size]; 298 } 299 300 301 /* primitve sorting */ 302 for (i = 0; i < realSize-1; i++) 303 { 304 for (j = 0; j < realSize-1-i; j++) 305 { 306 if (tempResult[j] > tempResult[j+1]) 307 { 308 unsigned char temp; 309 temp = tempResult[j+1]; 310 tempResult[j+1] = tempResult[j]; 311 tempResult[j] = temp; 312 } 313 } 314 } 315 /* insert result in destination */ 316 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = tempResult[size]; 317 } 318 } 319 } 320 free(filterMask); 321 free(tempResult); 322 } else /* not separable */ 323 { 324 int totalSize; /* the total number of samples in the filter */ 325 int k; 326 327 totalSize = realSize*realSize; 328 329 filterMask = (unsigned char *) malloc(sizeof(unsigned char) * (totalSize)); 330 for (y = 0 + size + 1; y < h - (size + 1); y++) 331 { 332 for (x = 0 + size + 1; x < w - (size + 1); x++) 333 { 334 for (c = 0; c < destSamplesPerPixel; c++) 335 { 336 k = 0; 337 for (i = 0; i < realSize; i++) 338 for (j = 0; j < realSize; j++) 339 filterMask[k++] = srcData[(y - size + i) * srcBytesPerRow + (x - size + j)*srcBytesPerPixel + c]; 340 341 /* primitve sorting */ 342 for (i = 0; i < totalSize-1; i++) 343 { 344 for (j = 0; j < totalSize-1-i; j++) 345 { 346 if (filterMask[j] > filterMask[j+1]) 347 { 348 unsigned char temp; 349 temp = filterMask[j+1]; 350 filterMask[j+1] = filterMask[j]; 351 filterMask[j] = temp; 352 } 353 } 354 } 355 356 /* insert result in destination */ 357 destData[destBytesPerRow*y + x*destBytesPerPixel + c] = filterMask[size*(realSize) + size]; /* center */ 358 } 359 } 360 } 361 free(filterMask); 362 } 363 } else 364 NSLog(@"Unrecognized median filter type."); 365 366 if (progPanel != nil) 367 { 368 [self setActivity:@"Done"]; 369 [self showProgress]; 370 } 371 372 [destImage setBitmapRep:destImageRep]; 373 [destImageRep release]; 374 [destImage autorelease]; 375 return destImage; 376} 377 378 379@end 380