Main Content

Calculate Global Statistics for Blocked Images

R2026b

This example shows how to calculate global statistics from a blocked image and then use the statistics to more accurately process blocks of the image.

The blockedImage object and apply function enable you to read and process individual blocks of an image. Block processing is necessary when working with images that are too large to load completely into memory. However, many image processing algorithms require global information about the image, which is not available when you are processing only one block of image data at a time.

This example demonstrates how to correct white balance using the White Patch Retinex algorithm. The White Patch Retinex algorithm estimates the scene illumination from the brightest pixels in the image. Block processing techniques are typically more useful for large images, but this example demonstrates the concepts using a small image that fits in memory.

Open and display an image with poor white balance. The image has a blue tint.

bim = blockedImage("foosball.jpg",BlockSize=[400 400]);
bigimageshow(bim)

Figure contains an axes object. The axes object contains an object of type bigimageshow.

The JPEG file format saves images in the gamma-corrected sRGB color space. Linearize the image by using the rgb2lin function. This operation can be performed independently on blocks.

bimLin = apply(bim,@(block) rgb2lin(block.Data));

Correct White Balance Using Local Statistics

Define a helper function, named whiteBalanceBlock, that performs white balance correction on a block of data. The whiteBalanceBlock function first estimates the illuminant based on a histogram of pixel values by using the illumwhite function. The whiteBalanceBlock function then applies the white balance correction by using the chromadapt function and converts the data to the sRGB color space for display.

function imWB = whiteBalanceBlock(im)
    illum = illumwhite(im);
    imWB = chromadapt(im,illum,ColorSpace="linear-rgb");
    imWB = lin2rgb(imWB);
end

Apply the whiteBalanceBlock function to blocks of the linearized blocked image by using the apply function.

bimWBLocal = apply(bimLin,@(block) whiteBalanceBlock(block.Data));

Display the white balanced image. You can see immediately that the results are incorrect. The problem is that each block was white balanced using a different estimated illuminant, rather than a single global illuminant for the entire scene.

bigimageshow(bimWBLocal)

Figure contains an axes object. The axes object contains an object of type bigimageshow.

Calculate Global Intensity Histogram

To estimate the illuminant of the entire scene, you can calculate the histogram of individual blocks, then add all of the histograms. Define a helper function, named calcBlockHist, that calculates the histograms of the red, green, and blue channels for a block by using the imhist function. The calcBlockHist function returns the histograms as fields in a structure, as required by the apply function for non-numeric and non-categorical output arguments.

function h = calcBlockHist(im)
    [countR,bins] = imhist(im(:,:,1));
    h = struct("countR",countR, ...
        "countG",imhist(im(:,:,2)), ...
        "countB",imhist(im(:,:,3)), ...
        "bins",bins);
end

Calculate the histograms for each block by using the apply function with the calcBlockHist function. The apply function returns a new blockedImage object whose source data is an in-memory array of structures. There is one element in the array for each block in the input blocked image.

bhist = apply(bimLin,@(block) calcBlockHist(block.Data));
bhist.Source{:}
ans = 6×9 struct array with fields:
    countR
    countG
    countB
    bins

Extract the source data into the workspace by using the gather function, then reformat the data into a vector of structures.

histRGB = gather(bhist);
histRGB = histRGB(:);

For each of the color channels, extract the histogram from all of the blocks by using the horzcat function and take the sum along the bins.

histR = sum(horzcat(histRGB.countR),2);
histG = sum(horzcat(histRGB.countG),2);
histB = sum(horzcat(histRGB.countB),2);

Because this example uses a small image that fits in memory, you can verify that the global histogram is summed correctly by comparing it to the output of the imhist function.

Call the imhist function on the original image, after linearization.

imLin = rgb2lin(imread("foosball.jpg"));
[histNormal,binsNormal] = imhist(imLin(:,:,1));

Compare the results. The histograms are numerically identical.

figure
subplot(1,2,1)
stem(histRGB(1).bins,histR,Color="r",Marker="none")
title("Summed Histogram")
subplot(1,2,2)
stem(binsNormal,histNormal,Color="r",Marker="none")
title("imhist Histogram")

Figure contains 2 axes objects. Axes object 1 with title Summed Histogram contains an object of type stem. Axes object 2 with title imhist Histogram contains an object of type stem.

Estimate the scene illumination from the top 5% brightest pixels. For each color channel, calculate the cumulative sum of the histogram in the reverse direction, and find the bin corresponding to the 95th percentile.

numPix = bim.Size(1)*bim.Size(2);
topPercentile = 5;

cumhistR = cumsum(histR,"reverse");
binR = find(cumhistR > (numPix*topPercentile/100),1,"last");
cumhistG = cumsum(histG,"reverse");
binG = find(cumhistG > (numPix*topPercentile/100),1,"last");
cumhistB = cumsum(histB,"reverse");
binB = find(cumhistB > (numPix*topPercentile/100),1,"last");

Store the estimated red, green, and blue values of the scene illuminant as a 3-element vector.

illum = [binR binG binB];

Scale the illuminant to the range [0, 1].

illum = (illum - 1) / (255)
illum = 1×3

    0.4980    0.6588    1.0000

Correct White Balance Using Global Statistics

Define a new helper function, named whiteBalanceGlobal, that performs white balance correction on a block of data using a specified illuminant.

function imWB = whiteBalanceGlobal(im,illum)
    imWB = chromadapt(im,illum,ColorSpace="linear-rgb");
    imWB = lin2rgb(imWB);
end

Apply the whiteBalanceGlobal function to the linearized blocked image by using the apply function.

bimWBGlobal = apply(bimLin,@(block) whiteBalanceGlobal(block.Data,illum));

Display the result. The image has good white balance and no block artifacts.

figure
bigimageshow(bimWBGlobal)

Figure contains an axes object. The axes object contains an object of type bigimageshow.

See Also

|

Topics