Im processing images from Php and I need to make a PNG from raw memory area. This memory area-format can be indexed (bytes) or RGB (R, G, B byte-byte-byte).
Basically it works like this for now:
for($i=0; $i < 100; $i++)
{
for($j=0; $j<100; $j++)
{
$byte = fread($F, pack('C');
// or
$R = fread($F, pack('C');
$G = fread($F, pack('C');
$B = fread($F, pack('C');
imagesetpixel($img, $j, $i, imagecolorallocate($img, $R,$G,$B);
}
}
and this is kinda slow. Im sure there must be a better way, any ideas?
Related
I store geometry polygons in MongoDb. It represents a delivery zones. The input parameter is coordinates point. How to check if this point is inside one of polygons?
I know ray-casting algorithm, but how to do that using MnogoDb engine? Is it opmimal way or better make calculations in script?
You can test if a point is within a polygon quite easily in PHP. This is likely to be easier than with Mongo
$vertx[10, 100, 150, 20]; // all x coordinates
$verty[10, 20, 100, 90]; // all y coordinates
$nvert = count($vertx);
$x = 50;
$y = 50;
$test = inpoly($nvert, $vertx, $verty, $x, $y); // true
function inpoly($nvert, $vertx, $verty, $testx, $testy) {
$i = $j = $c = 0;
for ($i = 0, $j = $nvert - 1; $i < $nvert; $j = $i++) {
if ((($verty[$i] > $testy) != ($verty[$j] > $testy)) && ($testx < ($vertx[$j] - $vertx[$i]) * ($testy - $verty[$i]) / ($verty[$j] - $verty[$i]) + $vertx[$i])) {
$c = !$c;
}
}
return $c;
}
I'm trying to save image as a real grayscale image. I believe the way I'm doing in PHP using imagefilter($im, IMG_FILTER_GRAYSCALE) or using the codes below are not saving the image as true grayscale but as RGB JPG of a grayscale image, as stated here.
function imagegreyscale(&$img, $dither=0) {
if (!($t = imagecolorstotal($img))) {
$t = 256;
imagetruecolortopalette($img, $dither, $t);
}
for ($c = 0; $c < $t; $c++) {
$col = imagecolorsforindex($img, $c);
$min = min($col['red'],$col['green'],$col['blue']);
$max = max($col['red'],$col['green'],$col['blue']);
$i = ($max+$min)/2;
imagecolorset($img, $c, $i, $i, $i);
}
}
function imagetograyscale($im)
{
if (imageistruecolor($im)) {
imagetruecolortopalette($im, false, 256);
}
for ($c = 0; $c < imagecolorstotal($im); $c++) {
$col = imagecolorsforindex($im, $c);
$gray = round(0.299 * $col['red'] + 0.587 * $col['green'] + 0.114 * $col['blue']);
imagecolorset($im, $c, $gray, $gray, $gray);
}
}
I compared the photo that my PHP code generated with the grayscale photo rendered by IrfanView. And the results are below. The first image shows a JPG without the word "Grayscale" while the second (by Irfanview) seems to be a real grayscale.
I need a true grayscale image to ensure my image is the smallest in file size without reducing dimension and quality further. So, how do I truly create a grayscale image using PHP?
Just for the sake of my question, lets say this function:
int imagecolorexact ( resource $image , int $red , int $green , int $blue )
We can call it up pretty easy like this:
$index = imagecolorexact($image, 0, 0, 0);
Obviously because we are talking the example in hand is about RGB colors, therefore the $red, $green and $blue values are between 0 and 255. This function returns an index of the pixel with that rgb compound.
What I need is to get the index of all pixels that their compound is NOT (0, 0, 0), so I'd thought to do it like this:
for($i = 0; $i <= 255; $i++) {
for($j = 0; $i <= 255; $i++) {
for($k = 0; $i <= 255; $i++) {
$index[] = imagecolorexact($image, $i, $j, $k);
}
}
}
But this will run 255*255*255 times which is alot I quess.
My question is:
Is there any way to simplify this?
Why am I asking this?
I am trying to change all the black pixels from an image to yellow, thus that would be:
$image = imagecreatefrompng("./test.png");
imagecolorset($image, imagecolorexact($image, 0, 0, 0), 255, 255, 0);
And I need to change all the NON black pixels from the same image into black, thus that will be (I quess?):
for($i = 1; $i <= 255; $i++) {
for($j = 1; $i <= 255; $i++) {
for($k = 1; $i <= 255; $i++) {
$index = imagecolorexact($image, $i, $j, $k);
imagecolorset($new, $value, 0, 0, 0);
}
}
}
Thus I am asking if there is a better, optimized way?
What I'd like here is a working, optimized version of my current code. While my function does return an array with actual results, I don't know if they are correct (I'm not a mathematics guru and I don't know Java code to compare my results against known implementations). Secondly, I'd like the function to be able to accept custom table sizes, but I don't know how to do that. Is table size equivalent to resampling the image? Am I applying the coefficients correctly?
// a lot of processing is required for large images
$image = imagecreatetruecolor(21, 21);
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
imagefilledellipse($image, 10, 10, 15, 15, $white);
print_r(imgDTC($image));
function imgDTC($img, $tableSize){
// m1 = Matrix1, an associative array with pixel data from the image
// m2 = Matrix2, an associative array with DCT Frequencies
// x1, y1 = coordinates in matrix1
// x2, y2 = coordinates in matrix2
$m1 = array();
$m2 = array();
// iw = image width
// ih = image height
$iw = imagesx($img);
$ih = imagesy($img);
// populate matrix1
for ($x1=0; $x1<$iw; $x1++) {
for ($y1=0; $y1<$ih; $y1++) {
$m1[$x1][$y1] = imagecolorat($img, $x1, $y1) & 0xff;
}
}
// populate matrix2
// for each coordinate in matrix2
for ($x2=0;$x2<$iw;$x2++) {
for ($y2=0;$y2<$ih;$y2++) {
// for each coordinate in matrix1
$sum = 1;
for ($x1=0;$x1<$iw;$x1++) {
for ($y1=0;$y1<$ih;$y1++) {
$sum +=
cos(((2*$x1+1)/(2*$iw))*$x2*pi()) *
cos(((2*$y1+1)/(2*$ih))*$y2*pi()) *
$m1[$x1][$y1]
;
}
}
// apply coefficients
$sum *= .25;
if ($x2 == 0 || $y2 == 0) {
$sum *= 1/sqrt(2);
}
$m2[$x2][$y2] = $sum;
}
}
return $m2;
}
My PHP function is a derivitive from this post in Java: Problems with DCT and IDCT algorithm in java. I have rewritten the code for php and readability. Ultimately, I am working on a script which will enable me to compare images and find similarities. The technique is outlined here: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html.
Thanks!
This is how I performed my DCT what I'm doing here is to perform a 1 dimension DCT on each row. Then I took the result an perform the DTC on each column it's faster.
function dct1D($in) {
$results = array();
$N = count($in);
for ($k = 0; $k < $N; $k++) {
$sum = 0;
for ($n = 0; $n < $N; $n++) {
$sum += $in[$n] * cos($k * pi() * ($n + 0.5) / ($N));
}
$sum *= sqrt(2 / $N);
if ($k == 0) {
$sum *= 1 / sqrt(2);
}
$results[$k] = $sum;
}
return $results;
}
function optimizedImgDTC($img) {
$results = array();
$N1 = imagesx($img);
$N2 = imagesy($img);
$rows = array();
$row = array();
for ($j = 0; $j < $N2; $j++) {
for ($i = 0; $i < $N1; $i++)
$row[$i] = imagecolorat($img, $i, $j);
$rows[$j] = dct1D($row);
}
for ($i = 0; $i < $N1; $i++) {
for ($j = 0; $j < $N2; $j++)
$col[$j] = $rows[$j][$i];
$results[$i] = dct1D($col);
}
return $results;
}
Most algorithm I found on internet assume that the input matrix is 8x8. That's why you multiplyed by 0.25.
In general you should multiply by sqrt(2 / N) a 1D matrix and here we are in 2D so sqrt(2/N1) * sqrt(2/N2). If you do this for N1 = 8 and N2 = 8:
sqrt(2/8)^2 = 2/8 = 1/4 = 0.25
The other thing was to multiply by 1/sqrt(2) X0 it's for 1D matrix here we are in 2D so you multiply when k1 = 0 or k2 = 0. When k1 = 0 and k2 = 0 you have to do it twice.
First you need to test your function so find any working implementation. And compare results from your implementation with the results of the working implementation (with the same input).
If you whant your code to be faster you can look at this paper http://infoscience.epfl.ch/record/34246/files/Vetterli85.pdf (the first 2 parts).
In your case you can't use a custom table size because it should match the image size (can be wrong).
Here i try to check image, but it has some "ellipses" of another color, and i try to smooth them by my color. But my code searches only for specific color, how to say him that for example 5% of difference is bad to?
How to find near my pixel all the same pixel and color them in another color?
<?php
function LoadJpeg($imgname)
{
$count = 0;
/* Attempt to open */
$im = #imagecreatefrompng($imgname);
$imagedata = getimagesize($imgname);
for($i=0; $i<$imagedata[0]; $i++){
for($j=0; $j<$imagedata[1]; $j++){
$rgb[$i][$j] = imagecolorat($im, $i, $j);
//echo $rgb[$i][$j];
//echo "<br>";
}
}
for($i=0; $i<$imagedata[0]-5; $i++){
for($j=0; $j<$imagedata[1]-5; $j++){
if (($rgb[$i][$j] == $rgb[$i+3][$j]) || ($rgb[$i][$j] == $rgb[$i][$j+3]))
{
#echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa";
$count = $count + 1;
//echo "<br> <br>";
//echo $count;
//$red = imagecolorallocate($im, 255, 255, 255);
imagesetpixel($im, $i, $j, 13437229);
}
}
}
return $im;
}
header('Content-Type: image/jpeg');
$img = LoadJpeg('1.png');
// echo "Image width is: " . $imagedata[0];
// echo "Image height is: " . $imagedata[1];
imagejpeg($img,null, 100);
?>
Main trouble is with strong ==, but some difference of this color must be catched by my if case.
What about calculating distance between each color component? If one of the components differ by more than 5 percents, return false:
// Returns RGB components of the color represented by an integer
function components($color) {
return array(($color >> 16) & 0xFF, ($color >> 8) & 0xFF, $color & 0xFF);
}
// Performs "similarity test" of 2 colors
function isSimilar($color1, $color2) {
$c1 = components($color1);
$c2 = components($color2);
for ($i = 0; $i < 3; $i++) {
$k = ($c1[$i] > $c2[$i]) ? ($c1[$i] - $c2[$i]) / $c2[$i] : ($c2[$i] - $c1[$i]) / $c1[$i];
if ($k > 0.05) return false;
}
return true;
}
// ...
if (isSimilar($rgb[$i][$j], $rgb[$i][$j + 3]) or isSimilar($rgb[$i][$j], $rgb[$i + 3][$j])) {
// ...
}
The code may require additional testing and tweaking, but I think you've got an idea.