Main Content

Block Processing Large Images

This example shows how to perform edge detection on a TIFF image by dividing the image into blocks. When working with large images, normal image processing techniques can sometimes break down. The images can either be too large to load into memory, or else they can be loaded into memory but then be too large to process.

To avoid these problems, you can process large images incrementally: reading, processing, and finally writing the results back to disk, one region at a time. Theblockprocfunction helps you with this process. Usingblockproc, specify an image, a block size, and a function handle.blockprocthen divides the input image into blocks of the specified size, processes them using the function handle one block at a time, and then assembles the results into an output image.blockprocreturns the output to memory or to a new file on disk.

First, consider the results of performing edge detection without block processing. This example uses a small image,cameraman.tif, to illustrate the concepts, but block processing is often more useful for large images.

file_name ="cameraman.tif"; I = imread(file_name); normal_edges = edge(I,"canny"); imshow(I) title("Original Image")

Figure contains an axes object. The axes object with title Original Image contains an object of type image.

imshow(normal_edges) title("Conventional Edge Detection")

Figure contains an axes object. The axes object with title Conventional Edge Detection contains an object of type image.

Now try the same task using block processing. Theblockprocfunction has built-in support for TIFF images, so you do not have to read the file completely into memory usingimread. Instead, call the function using the string filename as input.blockprocreads in one block at a time, making this workflow ideal for very large images.

When working with large images you will often use the "Destination"name-value argument to specify a file into whichblockprocwill write the output image. However, in this example you will return the results to a variable, in memory.

This example uses a block size of[50 50]. In general, choosing larger block sizes yields better performance forblockproc. This is particularly true for file-to-file workflows where accessing the disk will incur a significant performance cost. Appropriate block sizes vary based on the machine resources available, but should likely be in the range of thousands of pixels per dimension.

% You can use an anonymous function to define the function handle. The% function is passed a structure as input, a "block struct", with several% fields containing the block data as well as other relevant information.% The function should return the processed block data.edgeFun = @(block_struct) edge(block_struct.data,"canny"); block_size = [50 50]; block_edges = blockproc(file_name,block_size,edgeFun); imshow(block_edges) title("Block Processing - Simplest Syntax")

Figure contains an axes object. The axes object with title Block Processing - Simplest Syntax contains an object of type image.

Notice the significant artifacts from the block processing. Determining whether a pixel is an edge pixel or not requires information from the neighboring pixels. This means that each block cannot be processed completely separately from its surrounding pixels. To remedy this, use theblockprocname-value argument "BorderSize”to specify vertical and horizontal borders around each block. The necessary "BorderSize”varies depending on the task being performed.

border_size = [10 10]; block_edges = blockproc(file_name,block_size,edgeFun,"BorderSize", border_size);imshow (block_edges) title("Block Processing - Block Borders")

Figure contains an axes object. The axes object with title Block Processing - Block Borders contains an object of type image.

The blocks are now being processed with an additional 10 pixels of image data on each side. This looks better, but the result is still significantly different from the original in-memory result. The reason for this is that the Canny edge detector uses a threshold that is computed based on the complete image histogram. Since theblockprocfunction calls theedgefunction for each block, the Canny algorithm is working with incomplete histograms and therefore using varying thresholds across the image.

When block processing images, it is important to understand these types of algorithm constraints. Some functions will not directly translate to block processing for all syntaxes. In this case, theedgefunction allows you to pass in a fixed threshold as an input argument instead of computing it. Modify your function handle to use the three-argument syntax ofedge, and thus remove one of the "global" constraints of the function. Some trial and error finds that a threshold of0.09gives good results.

thresh = 0.09; edgeFun = @(block_struct) edge(block_struct.data,"canny",thresh); block_edges = blockproc(file_name,block_size,edgeFun,"BorderSize", border_size);imshow (block_edges) title("Block Processing - Borders & Fixed Threshold")

Figure contains an axes object. The axes object with title Block Processing - Borders & Fixed Threshold contains an object of type image.

The result now closely matches the original in-memory result. You can see some additional artifacts along the boundaries. These are due to the different methods of padding used by the Canny edge detector. Currently,blockproconly supports zero-padding along the image boundaries.

See Also

|

遗传代数ed Examples

More About