Pixel Drawing Algorithm - php

I need an example algorithm that will draw pixels one at a time on a grid based (x,y) system, and also color them based on an rbg value based on binary data that is provided in some form. I am looking for anything written in php or a php like language such as C, but that does not use any sort of library or graphics card api, as i am coding in php.
Here is something that i wrote in php, that uses random color values but it takes 15 seconds to render in an html canvas:
<?php
$r_max = 240;
$c_max = 320;
$row = -1;//-1 to offset while
while ($row<$r_max){
++$row;
for($column=0; $column<=$c_max; ++$column)
{
echo 'ctx.fillStyle = "rgb(', rand()%255, ',', rand()%255, ',', rand()%255, ')";';
echo 'ctx.fillRect(', $column, ',', $row, ',1,1);';
}
}
?>

Not really sure i quite understand your question but .. PHP has GD functions that include image allocate and setpixel calls, line drawing etc .. check here
oh and yes imagemagick also for more exotic uses

It seem you are trying to output JavaScript commands for drawing on a <canvas> tag. A faster way to draw the pixels might be to use moveTo and lineTo. Btw, why isn't you outer loop a for loop as well?
Doesn't
for($row=0; $row<=$r_max; ++$row) {
for($column=0; $column<=$c_max; ++$column) {
# draw pixel
}
}
seem more natural?

The issue is that you're generating code for each pixel. Instead, why not have the code write the pixel info to your favorite image format, then display that in the page? That's the most reasonable (to me) algorithmic solution... I'm not sure if it'll fit into what you're trying to do.

I cant use an image format, because it is not efficient for my usage. I am looking for some example code where an image might be displayed based on data, just so I can get an idea of how to do what I am doing at a rate faster then 15 seconds per render. The nested loops I included above are way to slow.

Related

box/spout - Massive memory usage when using hex color vs pre-defined colors

I'm using the Box/Spout library and it seems that using StyleBuilder with a custom hex color (e.g. 0000FF for blue) uses a ton of memory compared to using pre-defined colors such as Color::BLUE. Why would that be?
Relevant snippet:
//LOW MEMORY
$row[] = WriterEntityFactory::createCell('test', (new StyleBuilder())->setFontColor(Color::BLUE)->build());
//HIGH MEMORY
$row[] = WriterEntityFactory::createCell('test', (new StyleBuilder())->setFontColor($colorHex)->build());
Output:
setFontColor(Color::BLUE): Peak memory usage: 1666 KB
setFontColor($colorHex): Peak memory usage: 189436 KB
Full code:
(For demo purposes I'm loading a small 250x150 image to provide multiple color values)
<?php
require_once 'Spout/Autoloader/autoload.php';
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
//load an image
$img = imagecreatefrompng('input/test250x150.png');
$writer = WriterEntityFactory::createXLSXWriter();
$writer->openToFile('output/MyExcel.xlsx');
//height of the image
for($y=0; $y<150; $y++) {
//create or reset array to hold this row's cells
$row = [];
//width of the image
for($x=0; $x<250; $x++) {
//gets the pixel color
$index = imagecolorat($img, $x, $y);
$colorRGBArr = imagecolorsforindex($img, $index);
$colorHex = sprintf("%02x%02x%02x", $colorRGBArr['red'], $colorRGBArr['green'], $colorRGBArr['blue']);
//LOW MEMORY
//$row[] = WriterEntityFactory::createCell('test', (new StyleBuilder())->setFontColor(Color::BLUE)->build());
//HIGH MEMORY
$row[] = WriterEntityFactory::createCell('test', (new StyleBuilder())->setFontColor($colorHex)->build());
}
$writer->addRow(WriterEntityFactory::createRow($row));
}
$writer->close();
echo 'Peak memory usage: '.round(memory_get_peak_usage() / 1024).' KB';
?>
tl;dr
While the Spout can be improved, Excel isn't designed for large quantities of styles, so this isn't really a flaw of the library (you might want to rescind the issue)
The Story
Alright, there's a few things at play here.. the code I used to test is at the bottom of my post - the key relevant color functions are jonEg and jonEgQuant (which is a $by variable inside that can be tuned)
Styling in Excel is a little like HTML+CSS. Styles are defined initially in the file (in a header block) and then referenced by name (class) in the sheets. Fundamentally this suggests the Excel storage format was not designed for a plethora of styles, but only a handful that are reused on many cells
Spout hides the style-definition complexity from the user - if the style's already defined (ie. an exact style already exists) then it reuses that definition, otherwise a new style is defined
Spout builds an index of all styles, by serializing the style object and storing it in an array. At approximately 1749 bytes per style this index chews up memory (in addition to the actual style objects it has in memory to generate the file) - this could be improved in Spout
With this code I'm guaranteeing each cell has a different style (using the row/column position to define the red and green components of the color) - which is more extreme than your image-color-picking, but perhaps not by much (I cannot tell without the sample image). There are 16M colors available with an RGB triplet.. but our eyes cannot always detect a difference of a few points. For example it'll be clear in a red gradient that 255,254,253...128 looks smooth, but a single block of 255,254,253 randomly distributed will probably look like a single color. For anything but a primary color, this variance now applies in three dimensions (r, g, & b). The JPEG format exploits this (a combination of compression, and noise in rebuilding) - so color picking what might look like a uniform block will still return slightly different values each time
When you run my code with jonEg you get (100*150+1) 15001 styles, which takes (15001*1749/1024/1024) ~25MB of memory for the index in Spout alone. Again this index is needed to prevent every single cell in Excel having it's own style (but of course, in this contrived example I've made sure it's pointless - every cell does have it's own style) - this uses ~100MB of memory
When you run my code with jonEgQuant (leaving $by=16;) only 71 styles are needed (but this is pretty extreme rounding, allowing only 4096 colors in total), - this uses ~2MB of memory
When you set $by=4 (inside ColorBuilder::jonEgQuant) - you now have up to quarter of a million colours, 989 styles are needed, using ~7MB of memory (more to the point, this looks similar to jonEg when opened in Excel)
Spout includes a method to convert RGB decimal values into a string Color::rgb($r,$g,$b) - but this doesn't change the outcome (spoutDoc method)
A style has many more dimensions than this - I've used background colour, but there's foreground (your example), underline, bold, italic, font face, font-size - all of these multiply the style quantity (reducing the color space here addresses your documented problem, but could be undone by altering other style components)
Take Aways
It's not the use of hex codes, RGB values or constants that's the issue, it's the quantity of styles you're using
Reduce the number of styles you use - Excel doesn't expect a large count, Spout likewise isn't optimized for this. Compressing the color (by rounding values as with jonEgQuant) is one avenue
Improve the Spout style index mechanism, but notice only some of the memory is consumed by the index - it's not small, but it's not the only contributor - each style object is needed to generate the result. Removing this style cache (which for this contrived example doesn't help) brings memory usage to 40MB (and generates the same Excel file). 60% savings isn't nothing, but more styles makes for more memory usage, larger Excel files, and slower opening/rendering of those files
Testing notes
I dropped the image reading/color harvesting while testing since it may add to memory usage but not to the meat of the problem
With $colCount=250; (from your example) you exceed the 128MB default memory limit in PHP, better to set it $colCount=100; and you can run all the tests without changing that setting
I switched to setting background-color, it's easier to see the difference when opened in Excel
For each color generator (jonEg, spoutDoc, fixedEg, jonEgQuant) a different XLSX is generated (helps to see the file size and rendering differences)
The file sizes match the Excel complexity - jonEg is a 179KB file (and Excel struggles to open), while jonEgQuant is 43KB
Code
<?php
require_once 'Spout/Autoloader/autoload.php';
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Style\Color;
use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
// -- -- Set this to one of the method names on ColorBuilder (that isn't a helper)
$choice='jonEg';
// -- --
class ColorBuilder {
static $defaultBlue=255;
static function jonEg($x,$y) {return sprintf("%02x%02x%02x", $x, $y, static::$defaultBlue);}
static function spoutDoc($x,$y) {return Color::rgb($x, $y, static::$defaultBlue);}
static function fixedEg($x,$y) {return Color::BLUE;}
static function jonEgQuant($x,$y) {$by=16;return sprintf("%02x%02x%02x", static::_quantize($x,$by),static::_quantize($y,$by), static::_quantize(static::$defaultBlue,$by));}
//Helpers - don't use these for choice
static function validate(string $name):bool {
if ($name==null) return false;//Null or empty
if (substr($name,0,1)=='_') return false;//Private by convention
if ($name==='validate') return false;//Not the function you seek
return method_exists('ColorBuilder',$name);
}
private static function _quantize(int $i,int $by=16):int {return round($i/$by)*$by;}
}
function createRow($y,$color) {
$colCount=100;
$row = [];
for($x=0; $x<$colCount; $x++) {
$row[] = WriterEntityFactory::createCell('*', (new StyleBuilder())->setBackgroundColor(ColorBuilder::$color($x,$y))->build());
}
return $row;
}
function buildSheet($name) {
if (!ColorBuilder::validate($name)) {throw new Error('Invalid color provider');}
$writer = WriterEntityFactory::createXLSXWriter();
$writer->openToFile('output/'.$name.'.xlsx');
for($y=0; $y<150; $y++) {
$writer->addRow(WriterEntityFactory::createRow(createRow($y,$name)));
}
$writer->close();
}
buildSheet($choice);
echo 'Peak memory usage: '.round(memory_get_peak_usage() / 1024).' KB';
Tech: PHP 7.4.2 CLI, Spout: 3.1.0, Win: 7 x64 (I know), Coffee: Venti Dark

Compare Images using a database of images using ImageMagick?

I know I can compare two images (to check whether they are visually the same, not to check their file format, EXIF, etc.) using compareImages( Imagick $compare , int $metric ) function of ImageMagick library in PHP (also available in several other programming languages).
Sample codes to compare 2 images in PHP:
<?php
$image1 = new imagick("image1.png");
$image2 = new imagick("image2.png");
// TODO: have to resize 2 images to same dimension first
$result = $image1->compareImages($image2, Imagick::METRIC_MEANSQUAREERROR);
$result[0]->setImageFormat("png");
header("Content-Type: image/png");
echo $result[0]; // display the result
// TODO: Add exception handling
?>
But with thousands of images to compare against, this function seems to be inefficient, as it can only compare one by one. Is there any function that I can use to make a fingerprint (something like that) of an image, so that I can easily search in the database?
Methods I can think of:
Convert the image to Base64 string
Fetch few sample pixels from each image, store the colors in the database (but this method is not accurate)
Use Image recognition library (something like Machine Learning) to add some tags for each image, then search by tag (this method is not accurate as well)
(anything else?)
All suggestions are welcomed.
p.s. programming language does not necessary to be in PHP.
You could use the getImageSignature function, which will return a string containing the SHA-256 hash of the file.
So either loop over all images and add the image signature to your database of images, or just add the signature on every comparisson you perform.
Hope that helps.

How to create png from array of pixel color data in PHP?

Lets say I have an arrays of pixels. Basically an array of this data {x,y,r,g,b,a} for each pixel.
How would I go about converting all this data into an actual image file (png preferably)?
Could not find a solution. Any help would be very appreciated.
I had some time to code up a little example. You should be able to see and note that:
the red component increases towards the bottom of the image
the green component increases towards the right of the image
the blue component is absent
the alpha channel is random and between 0 (opaque) and 127 (fully transparent)
// Define width and height
$w=800;
$h=600;
// Create truecolour image so we can have infinitely many colours rather than a limited palette
$img=imagecreatetruecolor($w,$h);
imagesavealpha($img,true);
imagealphablending($img,false);
// Iterate over all pixels
for($y=0;$y<$h;$y++){
for($x=0;$x<$w;$x++){
$r = round(255*$y/$h);
$g = round(255*$x/$w);
$b = 0;
$alpha = rand(0,127);
$color = imagecolorallocatealpha($img,$r,$g,$b,$alpha);
imagesetpixel($img,$x,$y,$color);
}
}
// Save result
imagepng($img,"result.png");
I'll admit I haven't actually used this API, but looks like PHP has what you're looking for.
You create an image identifier with imagecreate or one of the related functions, then color in each pixel with imagesetpixel, using a color identifier created with imagecolorallocatealpha. From there you should be able to output as a PNG with imagepng.
It's worth noting that this image library seems to support drawing lines and shapes and other structures higher than the per-pixel level, so I'd also look into whether your code necessarily needs to build a big pixel array, rather than drawing the image some other way.

PHP - Find coordinates of group of pixel with similar color within a picture

I'm trying to get the coordinates of group of pixel with similar color in a picture using PHP. I think i have to use imagick, but after spending some time searching on the internet I cannot find exactly what I am looking for.
Let's say my base picture is entirely white with several colored shapes on it.
I want to get the coordinates of those shapes. It doesn't have to be exact coordinates, as long as the whole shape is in it.
Kind of like face recognition except much simpler.
Unfortunately I don't even know where to begin. I thought about comparing average pixel color every 5 pixels to map the whole picture, but it would be too time consuming.
There is probably already existing functions that does something like that, but I just can't find them.
I have full control over the server(Linux CentOs) so I can install any required additional library.
Thanks for your time.
There is a most common GD library for PHP.
A function called imagecolorat() returns the color at specified coordinates.
Yes, you need to compare every single pixel in the image or skip five pixels if that fits you needs.
What you're trying to do isn't as simple as it may seem. I don't think there is a specific function to break an image up into regions/sprites like you're trying to do.
However it's not too difficult to do with the code and pseudo-code below:
//Load the image
$imagick = new Imagick(realpath("../images/image.png"));
//Get access to the actual pixels of an image
$imageIterator = $imagick->getPixelRegionIterator(0, 0, $imagick->getImageWidth(), $imagick->getImageHeight());
foreach ($imageIterator as $row => $pixels) {
foreach ($pixels as $column => $pixel) {
$color = $pixel->getColor();
$spriteMapper->addPixel($color, $row, $column);
}
}
$imageIterator->syncIterator(); /* Sync the iterator, this is important to do on each iteration */
}
class SpriteMapper {
private $regions = array;
function addPixel($color, $row, $column) {
//If $color is background {
// return;
//}
//
//$found = false;
//foreach ($regions as $region) {
// if ($row and $column are next to $region){
// make $region larger
// $found = true;
// }
//}
//
//if ($found === false) {
// $regions[] = new Region($row, $column);
//}
}
}
You'll still need to define exactly what happens when regions overlap, as well as defining exactly what overlapping means. In your example image the bottom sprites appear to be separate, but you've considered them to be overlapping for marking the region.
Yes, doing this will be relatively slow - but so long as you're not doing this for every web-request it shouldn't be a problem.
btw you may wish to search https://gamedev.stackexchange.com/ for questions similar to this one, as this is something that

Imagick::resizeImage vs Imagick::scaleImage

What are the differences between resizeImage and scaleImage?
I need to resize an image if its size is > $myLimit
Example (pseudocode):
$myLimit = 1MB
user uplaod an image of 1000x1000 of 2MB
2MB > $myLimit
while( $imagefilesize > $myLimit ) {
resizeImageBy 0.9%;
}
//> output 900x900 image of 900 kB
In the while block, which of the two methods should I use?
Edit: I found something that could help: http://www.imagemagick.org/Usage/resize/ But could someone simplify that?
The difference between the two seems to be that scaleImage does a raw, pixel based resize, while resizeImage can use an interpolation filter:
imagick::INTERPOLATE_AVERAGE
imagick::INTERPOLATE_BICUBIC
imagick::INTERPOLATE_BILINEAR
...
that is likely to produce better results.
More on the various interpolation methods on Wikipedia.
Brilliant, their own documentation is awful... But ok: It looks to me like resizeImage is more powerful, and therefore the better choice... This link shows the usage along with some measurements for different filters.
According to my finding, when you want to scale down an image, use resizeImage. Because It gives you control over image quality and type of filter you want to use. But in the same case, scaleImage is also a good choice because when you have to scale down an image to let's say by factor of 10 and you are using resizeImage, then your resulting image will have many graphical errors.
In second case, when you have to scale up and image, then resizeImage will definetely have graphical error like while marks and lines and other stuff. In that case, scaleImage will come to rescue.

Categories