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