I am working on a project at a company that cuts designs using a laser cutter. The company recently developed a website that allows customers to upload any image of their choice. In order to cut the design printed on the image, the design has to be a stencil. So, I have to write a software that can analyze an image to find where it is non-stencilized. If the design turns out to be non-stencilized the system should output a message such as “Design not a stencil”. I imagine this would work by understanding where a group of white pixels are enclosed by a group of black pixels. If a white pixel is completely enclosed by black pixels, then the design is not a stencil. I am not quite sure how I can write a software that can check if a white pixel is completely enclosed by black pixels. Since all the previous code for the website is written in PHP, I would prefer to use PHP. Thanks in advance
In a nutshell, I think your question comes down to whether or not your image can be "flood-filled" - see Wikipedia.
So, if I just use ImageMagick at the command line to demonstrate, and flood-fill with magenta so you can see it:
convert valid.png -threshold 50% -fill magenta -draw 'color 0,0 floodfill' result.png
And if I do the same with the invalid stencil image:
convert invalid.png -threshold 50% -fill magenta -draw 'color 0,0 floodfill' result.png
So, the solution is to flood-fill and see if there are any white pixels left afterwards. In the actual code, I will fill with black rather than magenta because, that way, I have only to find if the brightest pixel after filling is black or not to know the answer:
So, again with ImageMagick. Flood-fill with black and see if brightest pixel after filling is black (0) or white (255 or 65535):
convert valid.png -threshold 50% -fill black -draw 'color 0,0 floodfill' -format "%[max]" info:
0
and now the invalid stencil:
convert invalid.png -threshold 50% -fill black -draw 'color 0,0 floodfill' -format "%[max]" info:
65535
There is one little wrinkle - if the top-left pixel is not white, or the black parts touch the edge of the picture and stop the flood-fill flowing around the edges of the picture. And there is a simple solution to both, just add a 1-pixel wide white border all around the image before you start to ensure the top-left pixel is white and that the "paint" can flow all the way around the edges of image:
convert input.png -bordercolor white -border 1 .... <as before> ...
PHP Version
PHP is not my native programming language so there may be other, better ways of doing things but this seems to work ok...
<?php
# Load the input image and get its size
$name="invalid.png";
$image=imagecreatefrompng($name);
$size=getimagesize($name);
# Threshold the image to only contain pure black and pure white
imagefilter($image,IMG_FILTER_GRAYSCALE);
imagefilter($image,IMG_FILTER_CONTRAST,-1000);
# Flood fill white areas with black
$black = imagecolorallocate($image,0,0,0);
imagefilltoborder($image,0,0,$black,$black);
$allblack=1;
# Scan the image and see if there are any non-black pixels
for($i=0;$i<$size[0];$i++){
for($j=0;$j<$size[1];$j++){
$thisColor = imagecolorat($image,$i,$j);
if($thisColor!=0){
$allblack=0;
break;
}
}
}
printf("%s: %d\n",$name,$allblack);
# Write output image
imagepng($image,"result.png");
?>