View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.image.processing.algorithm;
31  
32  import org.openimaj.citation.annotation.Reference;
33  import org.openimaj.citation.annotation.ReferenceType;
34  import org.openimaj.image.FImage;
35  import org.openimaj.image.mask.AbstractMaskedObject;
36  import org.openimaj.image.processor.ImageProcessor;
37  
38  /**
39   * An image processor that performs contrast equalisation
40   * in a robust manner with a mask.
41   * 
42   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
43   */
44  @Reference(
45  		type = ReferenceType.Article,
46  		author = { "Tan, Xiaoyang", "Triggs, Bill" },
47  		title = "Enhanced local texture feature sets for face recognition under difficult lighting conditions",
48  		year = "2010",
49  		journal = "Trans. Img. Proc.",
50  		pages = { "1635", "", "1650" },
51  		url = "http://dx.doi.org/10.1109/TIP.2010.2042645",
52  		month = "June",
53  		number = "6",
54  		publisher = "IEEE Press",
55  		volume = "19"
56  	)
57  public class MaskedRobustContrastEqualisation extends AbstractMaskedObject<FImage> implements ImageProcessor<FImage> {
58  	double alpha = 0.1;
59  	double tau = 10;
60  
61  	/**
62  	 * Construct with no mask set
63  	 */
64  	public MaskedRobustContrastEqualisation() {
65  		super();
66  	}
67  
68  	/**
69  	 * Construct with a mask.
70  	 * @param mask the mask.
71  	 */
72  	public MaskedRobustContrastEqualisation(FImage mask) {
73  		super(mask);
74  	}
75  	
76  	@Override
77  	public void processImage(FImage image) {
78  		//1st pass
79  		image.divideInplace(firstPassDivisor(image, mask));
80  		
81  		//2nd pass
82  		image.divideInplace(secondPassDivisor(image, mask));
83  		
84  		//3rd pass
85  		for (int y=0; y<image.height; y++) {
86  			for (int x=0; x<image.width; x++) {
87  				if (mask.pixels[y][x] == 1) {
88  					image.pixels[y][x] = (float) (tau * Math.tanh(image.pixels[y][x] / tau));
89  				} else {
90  					image.pixels[y][x] = 0;
91  				}
92  			}
93  		}
94  	}
95  	
96  	float firstPassDivisor(FImage image, FImage mask) {
97  		double accum = 0;
98  		int count = 0;
99  		
100 		for (int y=0; y<image.height; y++) {
101 			for (int x=0; x<image.width; x++) {
102 				if (mask.pixels[y][x] == 1) {
103 					double ixy = image.pixels[y][x];
104 					
105 					accum += Math.pow(Math.abs(ixy), alpha);
106 					count++;
107 				}
108 			}
109 		}
110 		
111 		return (float) Math.pow(accum / count, 1.0 / alpha);
112 	}
113 	
114 	float secondPassDivisor(FImage image, FImage mask) {
115 		double accum = 0;
116 		int count = 0;
117 		
118 		for (int y=0; y<image.height; y++) {
119 			for (int x=0; x<image.width; x++) {
120 				if (mask.pixels[y][x] == 1) {
121 					double ixy = image.pixels[y][x];
122 					
123 					accum += Math.pow(Math.min(tau, Math.abs(ixy)), alpha);
124 					count++;
125 				}
126 			}
127 		}
128 		
129 		return (float) Math.pow(accum / count, 1.0 / alpha);
130 	}
131 }