Technical FAQs for "scanfix-xpress-.net"

Question

Using ScanFix Xpress (as illustrated in the ImageCleanUp sample) I can deskew an image, but the leftover blank space is filled with a user-specified pad color, which might clash horribly with the edges of the original image. Is it possible to automatically detect a matching pad color before executing a deskew operation?

Answer

A simple approach would be to crop off the four edges of the image, specified perhaps by a percentage of width/height floor-bound by a minimum pixel count, then use the RGBColorCount method from ImagXpress on each edge to generate a histogram for each color channel, find the most frequent or average intensity (or some combination of the most frequent and the average), and then find the average intensity among all four edges. Then this resultant color could be used as the pad color for the image when it is deskewed.

For example, you can crop out portions of an image using the Crop method of the Processor class…

// Crop out the top edge of the image referred to by proc.Image
Rectangle cropRectangle = new Rectangle(0, 0, inputImg.Width, verticalSliceSize);
_processor.Crop(cropRectangle);
return proc.Image;

We can do this for all four edges of the image. Then, for each edge, we can determine the frequencies at which each intensity occurs in the image’s pixel grid using the RGBColorCount Method…

int[] redHistogram, greenHistogram, blueHistogram;
_processor.Image = edge;
_processor.RGBColorCount(out redHistogram, out greenHistogram, out blueHistogram);

…now, redHistogram, greenHistogram, and blueHistogram will contain the frequencies of red, green, and blue intensities (0 to 255), respectively. We can use this data to extrapolate either the most frequent or the average intensity (or some combination of the two) in each channel. We can then construct RGB triplets representing the detected border color for that edge, and then average the values for each edge to get the appropriate overall pad color. 

For example (using an average intensity)…

public int[] DetectEdgeAverageColor(ImageX edge)
{
    int[] averageRGB = new int[] { 0, 0, 0 };
    int[] redHistogram, greenHistogram, blueHistogram;
    _processor.Image = edge;
    _processor.RGBColorCount(out redHistogram, out greenHistogram, out blueHistogram);

    int numPixels = edge.Width * edge.Height;
    averageRGB[0] = findAverageIntensity(redHistogram, numPixels);
    averageRGB[1] = findAverageIntensity(greenHistogram, numPixels);
    averageRGB[2] = findAverageIntensity(blueHistogram, numPixels);
    

    return averageRGB;
}

private int findAverageIntensity(int[] frequencies, int numPixels)
{
    double averageIntesntity = 0;
    for (int intensityValue = 0; intensityValue < 256; intensityValue++)
    {
        int frequencyOfThisIntesity = frequencies[intensityValue];
        averageIntesntity += (intensityValue * frequencyOfThisIntesity);
    }
    averageIntesntity /= numPixels;
    return (int)Math.Round(averageIntesntity);
}

This should produce an RGB triplet representing a color similar to the edges of the image to be deskewed.