# Can I control per-pixel contrast in an image?

Is there any way to control per-pixel contrast? E.g., a way to set an upper or lower limit on the contrast between pixels?

The closest thing I've found is a high-pass filter of an n-pixel radius, inverted and applied as an overlay layer in Photoshop. Other kinds of filters, such as median, blurs, and traditional contrast adjustment, produce a result which is similar to my goal in some circumstances, but for the whole image, rather than only pixel pairs over a given contrast threshold, or proportionally based on contrast.

Does this concept have a name? Is there an easier way to do what I'm attempting?

[Edit: And is there any free or affordable software which can be coerced to do this?]

• Can you define your notion of per-pixel contrast a little more specifically? I'm having trouble following it. Really interesting question though. Commented May 10, 2013 at 21:40

By per-pixel I assume that you mean only the surrounding pixels should influence the pixel value. Unfortunately changing the pixel value in response to one adjacent pixel means the contrast with the others could also change. Kind of like a 'chain reaction' of changes.

For example, saw we had $I = [0,7,11]$ and we wanted a maximum contrast of 5. Going from the left we change 7 to 5, which then requires 11 to be changed to 10.

Maximum Contrast

One way per pixel maximum contrast can be done is by using morphological operators. Specifically, performing a dilation (or erosion) with a pyramid structuring element based on the maximum contrast value, $c$. For dilation, the structuring element is

... ... ... ... ... ... ... ... ...
... -3c -3c -3c -3c -3c -3c -3c ...
... -3c -2c -2c -2c -2c -2c -3c ...
... -3c -2c -1c -1c -1c -2c -3c ...
... -3c -2c -1c   0 -1c -2c -3c ...
... -3c -2c -1c -1c -1c -2c -3c ...
... -3c -2c -2c -2c -2c -2c -3c ...
... -3c -3c -3c -3c -3c -3c -3c ...
... ... ... ... ... ... ... ... ...


The size of the structuring element will depend on $c$ and the range of pixel values. Assuming pixel values are in [0,255], size will be N x N pixels where N = 2*floor(255/c) + 1, e.g.

c = 100

-200 -200 -200 -200 -200
-200 -100 -100 -100 -200
-200 -100    0 -100 -200
-200 -100 -100 -100 -200
-200 -200 -200 -200 -200


Dilation increases pixel values to enforce the maximum contrast, erosion decreases pixel values. In out example above, dilation would give $I = [2,7,11]$, erosion would give $I = [0,5,10]$.

Minimum Contrast

Enforcing a minimum contrast is not going to give you good results. Imagine having a minimum contrast in a flat area, it will turn it into a ramp. For this operation it is better to look at filters that enhance edges etc.

MATLAB code

MATLAB code to do this:

clear all; close all;

% Test image
I = randi(256,10,10)-1;
imagesc(I); colorbar; title('test image'); pause;

% Constrast settings
c = 10;
maxPixelValue = 255;

% Structuring element
halfN = floor(maxPixelValue/c);
N = 2*halfN + 1;
[x,y] = ndgrid(-halfN:halfN);
stDH(:,:,1) = abs(x) * -c;
stDH(:,:,2) = abs(y) * -c;
stDH = min(stDH,[],3);
stD = strel('arbitrary',ones(N),stDH);
stE = strel('arbitrary',ones(N),stDH);
imagesc(stDH); colorbar; title('structuring element'); pause;

% Dilation result
Id_max = imdilate(I,stD);
imagesc(Id_max); colorbar; title('max contrast (dilation)'); pause;
imagesc(I-Id_max); colorbar; title('diff with original'); pause;

% Erosion result
Ie_max = imerode(I,stE);
imagesc(Ie_max); colorbar; title('max contrast (erosion)'); pause;
imagesc(I-Ie_max); colorbar; title('diff with original'); pause;

%% Min contrast
stD = strel('arbitrary',ones(N),-stDH);
stE = strel('arbitrary',ones(N),-stDH);

% Dilation result
Id_max = imdilate(I,stD);
imagesc(Id_max); colorbar; title('min contrast (dilation)'); pause;
imagesc(I-Id_max); colorbar; title('diff with original'); pause;

% Erosion result
Ie_max = imerode(I,stE);
imagesc(Ie_max); colorbar; title('min contrast (erosion)'); pause;
imagesc(I-Ie_max); colorbar; title('diff with original'); pause;

• Fascinating; could you recommend any software to accomplish this apart from Matlab? Commented May 12, 2013 at 14:33
• How about ImageJ? rsbweb.nih.gov/ij ... To extend it's functionality you have to add some plugins (or write your own), maybe the greyscale morphology plugin could work. rsbweb.nih.gov/ij/plugins/gray-morphology.html. P.S. what is the application? If it is for photo-enhancement I find the 'clarity' adjustment in Photoshop Lightroom gives really good results for localised contrast enhancement. Commented May 13, 2013 at 2:44
• The goal is the manipulation of terrain data, where "per-pixel contrast" is roughly analogous to "slope". Commented May 13, 2013 at 15:14
• For the record: the morphological operators did exactly what I wanted, and I used them in these webGL demos: github.com/meetar/heightmap-demos Commented Nov 29, 2021 at 21:33

You could certainly write some software to do this, and leverage graphicsmagick. Not familiar with photoshop but you could probably write a filter to do it as well. It may be challenging to get a satisfactory result though because your contrast delta in some areas of the image might end up different than the deltas in another area, due to a snowball effect of adjusting contrast on a per pixel basis. It might be more wise to break the image up into successively smaller chunks, adjusting contrast of each chunk at each stage in order to maintain a greater consistency overall. The level adjustment algorithm would be the same for each stage, but you would adjust all the pixels in each chunk at once. Just an exemplary thought.

• Graphicsmagick looks likely -- do you know whether it allows custom filters? Commented May 12, 2013 at 14:39
• I have only used GM as a library; you can use it in C++ code to read in your image and apply arbitrary per-pixel or pixel group algorithms of your choosing, and then display or save the resulting image. There are numerous built in processing methods but pixels can simply be accessed and modified according to their integer (R,G,B) values. Commented May 13, 2013 at 16:47

It is possible to work directly in "contrast domain" of an image, fiddling with local contrast values and then finding image whose contrast domain best matches the adjusted one:

see R. Mantiuk, K. Myszkowski: "A Perceptual Framework for Contrast Processing of High Dynamic Range Images": http://www.mpi-inf.mpg.de/~mantiuk/contrast_domain/

Of course, it depends on how you define the contrast. The one used in above paper is differences in neighboring pixels (this works the similar way as gradient domain processing).

The simplest definition is just color contrast, which can be adjusted using traditional filters (e.g. converting each color channel to $<-1,1>$ and then multiplying the value by a contrast factor $c$, clamp back to $<-1,1>$ and convert back to $<0,255>$ or whatever scale you use. The contrast is increased for $c>1$ and decreased for $0>c>1$.

• Hmm… The pfstools package is interesting, but at the moment, I don't want to adjust image-wide contrast profiles, I'm only interested in "fiddling with local contrast values". :) Commented May 12, 2013 at 14:52