Prefer to read without ads? Become a member — from $10/month — and support the work. Already a member? Log in to read ad-free on this device.

15.9 Source Code

When working on optimized normalized cross-correlation code, it does not take long to realize that it’s surprisingly difficult and error-prone. Converting the sums to correlation coefficients, as described in Section 15.1, must be done carefully due to the precision characteristics of float versus int (float has a greater dynamic range, but only 24 bits of precision); it is good practice to develop separate subroutines that report the computed sums, to root cause whether a given implementation is reporting incorrect coefficients due to incorrect sums or an incorrect coefficient computation. Also, the sums can be bitwise-compared with CPU results, while the float-valued coefficients must be fuzzily compared against an epsilon value.

The different implementations of correlation are broken out into separate header (.cuh) files, and the kernels that emit sums as well as correlation coefficients are separate.

File Description
corrTexTex.cuh / corrTexTexSums.cuh Image and template both read from texture (§15.2)
corrTexConstant.cuh / corrTexConstantSums.cuh Image from texture, template from constant memory (§15.3)
corrShared.cuh / corrSharedSums.cuh Image staged through shared memory (§15.4)
corrShared4Dp4a.cuh / corrShared4Dp4aSums.cuh corrShared() with four pixels packed per DP4A instruction; a teaching intermediate (§15.5)
corrShared4Dp4aIlp.cuh DP4A plus two-column instruction-level parallelism—the fastest kernel (§15.5)
normalizedCrossCorrelation.cu Test program for the spatial kernels (§15.2–15.5)
sat.cuh Summed-area-table primitive: naive/CUB/transpose-free-DLB builds and the four-corner query (§15.8)
integralImage.cu Driver that benchmarks and validates the three summed-area-table builds (§15.8)
corrBankTC.cu Many-template NCC via an INT8 Tensor-Core GEMM (§15.6)
corrFFT.cu Single-template NCC via cuFFT (§15.7)

The normalizedCrossCorrelation.cu program tests both the functionality and the performance of the kernels. By default, it loads coins.pgm and detects the dime in the lower right corner. The dime is located at (210,148) and is 52×52 pixels in size. The program also writes the performance measurements to stdout, e.g.:

$ normalizedCrossCorrelation --padWidth 1024 --padHeight 1024 -wTemplate 16 -hTemplate 16
corrShared: 1267.13 Mpix/s  324.38Gtpix/s
corrShared4Dp4a: 1301.92 Mpix/s 333.29Gtpix/s
corrShared4Dp4aIlp: 7548.28 Mpix/s  1932.36Gtpix/s
corrTexConstant: 791.58 Mpix/s  202.64Gtpix/s
corrTexTex: 403.15 Mpix/s   103.21Gtpix/s

The program supports the following command line options:

--input <filename>: specify the input filename (default: coins.pgm)

--output <filename>: optionally specify the output filename. If specified, the program will write a PGM file containing an intensity map (like Figure 15-3) to this filename.

--padWidth <width>: pad the width of the image.

--padHeight <height>: pad the height of the image.

--xTemplate <value>: specify the X coordinate of the upper left corner of the template.

--yTemplate <value>: specify the Y coordinate of the upper left corner of the template.

--wTemplate <value>: specify the width of the template.

--hTemplate <value>: specify the height of the template.