Chapter 3. Visual Debugging Aids

When creating tools to modify images, it is often vital to have an model of the image data. Using alternate ways to visualize the data often reveals other properties and/or enhances our ability to observe features.

Histogram

A histogram shows the distribution of low/high (dark/light) samples within an image.

The bars in the left portion of the histogram shows the amount of dark/shadow samples in the image, in the middle the mid-tones are shown and to the right the highlights.

A low contrast image will have a histogram concentrated around the middle. A dark image will have most of the histogram to the right, a bright image uses mostly the right hand side of the histogram, while a high contrast image will have few mid-tone values; making the histogram have an U shape.

The histogram in Figure 3.1, “histogram” spans from left to right, so it makes good use of the available contrast. The image is overexposed beyond repair, this can be seen from the clipping at the right hand (highlight side). This means details of the clouds in the sky are permantently lost.

Figure 3.1. histogram -- utility function to set the RGB color for a rectangular region
function draw_rectangle(x0,y0,x1,y1,r,g,b)
for y=y0,y1 do
for x=x0,x1 do
set_rgb (x,y, r,g,b)
end
end
end

function draw_histogram(bins)
-- first we count the number of pixels belonging in each bin
local bin = {}
for i=0,bins do
bin[i]=0
end
for y=0, height-1 do
for x=0, width-1 do
l,a,b = get_lab (x,y)
bin[math.floor(bins * l/100)] = bin[math.floor(bins * l/100)] + 1
end
progress (y/height/2)
end
-- then we find the maximum number of samples in any bin
max = 0
for i=0,bins do
if bin[i]>max then
max=bin[i]
end
end
-- and then plot the histogram over the original image.
for i=0,bins do
draw_rectangle((width/(bins+1))*i, height-(bin[i]/max*height),
(width/(bins+1))*(i+1), height, 1, 1, 0)
progress (i/bins/2+0.5)
end
end

draw_rectangle(0,0,width,height,0,0,0)
draw_histogram(64)

Chromaticity Diagram

A chromaticity diagram tells us about the color distribution and saturation in an image. All pixels are plotted inside a color circle, distance to center gives saturation and angle to center specifies hue. If the white balance of an image is wrong it can most often be seen by a non centered chromaticity diagram.

Origin in analog widget A chromaticity scope in the analog television world were traditionally created by conncting an oscilloscope to the color components of a video stream. This allowed debugging setting of the equipment handling the analog image data.

Figure 3.2. chromaticity diagram function draw_rectangle(x0,y0,x1,y1,r,g,b)
for y=y0,y1 do for x=x0,x1 do set_rgb (x,y, r,g,b) end end
end

function draw_chromascope(scale)
if width > height then
scale = (scale * 100)/height
else
scale = (scale * 100)/width
end
for y=0, height-1 do
for x=0, width-1 do
l,a,b = get_lab (x,y)
set_lab ( (a * scale) + width*0.5,
(b * scale) + height*0.5,
l,a,b)
end
progress (y/height)
end
end

draw_rectangle(0,0,width,height,0,0,0)
draw_chromascope(4)
draw_rectangle(width*0.5,0,width*0.5,height,1,1,1)
draw_rectangle(0,height*0.5,width,height*0.5,1,1,1)

Luminance Profile

A luminiosity profile is the visualization of the luminance along a straight line in the image. The luminance plot allows a more direct way to inspect the values of an image than a histogram does.

In Figure 3.3, “luminance profile” the yellow curve indicates which line the profile is taken from, the brightness of the snow as well as the relative brightness of the sky compared to the mountains is quite apparent.

Figure 3.3. luminance profile function draw_rectangle(x0,y0,x1,y1,r,g,b)
for y=y0,y1 do for x=x0,x1 do set_rgb (x,y, r,g,b) end end
end

function lerp(v0,v1,r)
return v0*(1.0-r)+v1*r
end

function draw_line(x0,y0,x1,y1,r,g,b)
for t=0,1.0,0.001 do
x = lerp(x0,x1,t)
y = lerp(y0,y1,t)
set_rgb (x,y,r,g,b)
end
end

function lumniosity_profile(x0,y0,x1,y1)
for y=0,height-1 do
for x=0,width-1 do
l,a,b = get_lab (x,y)
set_lab (x,y, l*0.3,a,b)
end
end
draw_line(x0,y0,x1,y1,1,1,0)
prev_x, prev_y = -5, height*0.5
for x=0,width do
xsrc = lerp(x0,x1, x/width)
ysrc = lerp(y0,y1, x/width)
l,a,b = get_lab (xsrc,ysrc)
y = height - (l/100) * height
draw_line (prev_x, prev_y, x,y, 1,1,1)
prev_x, prev_y = x, y
end
end

lumniosity_profile(0,height*0.2, width,height*0.5)