What am I doing wrong in this loop for image pixels? - php

<?php
$img = imagecreatefrompng("cuack.png");
$imagew = imagesx($img);
$imageh = imagesy($img);
$width = array();
$heigth = array();
$x = 0;
$y = 0;
for ($x = 0; $x <= $imagew; $x++) {
$rgba = imagecolorat($img,$x,1);
$alpha = ($rgba & 0x7F000000) >> 24;
var_dump($alpha);
}
for ($x = 0; $x <= $imageh; $x++) {
}
I'm trying to check every pixel in an image for transparent pixels, but I'm receiving the following error:
Notice: imagecolorat() [function.imagecolorat]: 1920,1 is out of bounds in C:\www\index.php on line 18

The boundaries start at 0 and thus extend to width − 1 and height − 1 in each direction. Therefore, the <= $imagew needs to be < $imagew. Likewise for <= $imageh.
Width and height just tell you how many rows and columns of pixels there are, not the maximum row or column index (which is one lower).
To walk the whole image, just use two nested loops:
for ($y = 0; $y < $imageh; $y++) {
for ($x = 0; $x < $imagew; $x++) {
// do whatever you want with them in here.
}
}

Related

Storing Image pixel values in a 2D array using PHP and then access them using a loop

I have this code that I tried to store Image pixel values in 2D Array and then try to access them so that I can recreate the same Image from the pixels stored in the array, the following was what I was trying to do but it only access the array in 1 Dimension, any who can help will much appreciate it
$resource = imagecreatefromjpeg("Broadway_tower_edit.jpg");
$width = 3;
$height = 3;
$arrayPixels = array();
//put pixels values in an array
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
// pixel color at (x, y)
$color = imagecolorat($resource, $x, $y);
$arrayPixels1 = array("$color");
//$myArray[$x][$y] = array('item' => "$color");
$arrayPixels[] = $arrayPixels1;
}
}
//access pixel values an try to create a image
$img = imagecreatetruecolor($width, $height);
for ($y = 0; $y < $height; ++$y) {
for ($x = 0; $x < $width; ++$x) {
imagesetpixel($img, $x, $y, $arrayPixels[$y][$x]);
}
}
// Dump the image to the browser
header('Content-Type: image/jpg');
imagejpeg($img);
// Clean up after ourselves
imagedestroy($img);
Your array is as you say, just the rows, you need to either build up each row and then add it to a list of rows
$arrayPixels = array();
//put pixels values in an array
for($x = 0; $x < $width; $x++) {
$row = array();
for($y = 0; $y < $height; $y++) {
// pixel color at (x, y)
$row[] = imagecolorat($resource, $x, $y);
}
$arrayPixels[] = $row;
}
or do the same as you do when you re-create the image and use the x and y co-ords...
//put pixels values in an array
for($x = 0; $x < $width; $x++) {
for($y = 0; $y < $height; $y++) {
// pixel color at (x, y)
$arrayPixels[$y][$x] = imagecolorat($resource, $x, $y);
}
}

GD Image Library merge 2 images with "Collision Detection"

I have two images, large text on white background. The length varies but the text is always aligned to the left, so there is basically free space on the right side of each image. I now want to merge these two images into one and move them as closely together as possible without having the texts "collide".
I thought of somehow checking on a per pixel column base if there's another color than white (starting from the right side), so I know after how many pixels the text starts.
Found the solution, neat function to strip all the whitespace from an image:
function stripWhitespace($img) {
//find the size of the borders
$b_top = 0;
$b_btm = 0;
$b_lft = 0;
$b_rt = 0;
//top
for(; $b_top < imagesy($img); ++$b_top) {
for($x = 0; $x < imagesx($img); ++$x) {
if(imagecolorat($img, $x, $b_top) != 0xFFFFFF) {
break 2; //out of the 'top' loop
}
}
}
//bottom
for(; $b_btm < imagesy($img); ++$b_btm) {
for($x = 0; $x < imagesx($img); ++$x) {
if(imagecolorat($img, $x, imagesy($img) - $b_btm-1) != 0xFFFFFF) {
break 2; //out of the 'bottom' loop
}
}
}
//left
for(; $b_lft < imagesx($img); ++$b_lft) {
for($y = 0; $y < imagesy($img); ++$y) {
if(imagecolorat($img, $b_lft, $y) != 0xFFFFFF) {
break 2; //out of the 'left' loop
}
}
}
//right
for(; $b_rt < imagesx($img); ++$b_rt) {
for($y = 0; $y < imagesy($img); ++$y) {
if(imagecolorat($img, imagesx($img) - $b_rt-1, $y) != 0xFFFFFF) {
break 2; //out of the 'right' loop
}
}
}
//copy the contents, excluding the border
$newimg = imagecreatetruecolor(
imagesx($img)-($b_lft+$b_rt), imagesy($img)-($b_top+$b_btm));
imagecopy($newimg, $img, 0, 0, $b_lft, $b_top, imagesx($newimg), imagesy($newimg));
return $newimg;
}
From here: Crop whitespace from image in PHP

How to calculate Discrete Cosine Transform (DCT) in PHP?

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).

Remove black edges from existing image using the GD library

I'm downloading an image that already has black edges. Note: this isn't a result of me resizing an image. How can I use the GD library to detect and remove these black edges?
UPDATE
This is the cropped image using the script
I was able to come up with a time-consuming fix to this. Do the images being stored need to be stored with those black borders? It'd be much better if you could run every image with the black borders through the following script (using php to loop through every image in the directory) and let php override the old, black-bordered image with the new, borderless image.
The approach I took was to create 4 loops:
To look at black borders on the right (loop through x -> loop through y)
To look at black borders on the left (loop through x -> loop through y)
To look at black borders on the bottom (loop through y -> loop through x)
To look at black borders on the top (loop through y -> loop through x)
Now, each of these loops had another loop in them which would loop through the other coordinate (ie., x->y or y->x). If the inner loop found that one of the pixels lying on the outer loop's line wasn't black, it broke the whole look. If it didn't find that, it would increase one to the counter.
At the end, we simply create a new image with the new dimensions and copy from the new to the old one.
<?php
$image_path = "jcMHt.jpg";
$jpg = imagecreatefromjpeg($image_path);
$black = array("red" => 0, "green" => 0, "blue" => 0, "alpha" => 0);
$removeLeft = 0;
for($x = 0; $x < imagesx($jpg); $x++) {
for($y = 0; $y < imagesy($jpg); $y++) {
if(imagecolorsforindex($jpg, imagecolorat($jpg, $x, $y)) != $black){
break 2;
}
}
$removeLeft += 1;
}
$removeRight = 0;
for($x = imagesx($jpg)-1; $x > 0; $x--) {
for($y = 0; $y < imagesy($jpg); $y++) {
if(imagecolorsforindex($jpg, imagecolorat($jpg, $x, $y)) != $black){
break 2;
}
}
$removeRight += 1;
}
$removeTop = 0;
for($y = 0; $y < imagesy($jpg); $y++) {
for($x = 0; $x < imagesx($jpg); $x++) {
if(imagecolorsforindex($jpg, imagecolorat($jpg, $x, $y)) != $black){
break 2;
}
}
$removeTop += 1;
}
$removeBottom = 0;
for($y = imagesy($jpg)-1; $y > 0; $y--) {
for($x = 0; $x < imagesx($jpg); $x++) {
if(imagecolorsforindex($jpg, imagecolorat($jpg, $x, $y)) != $black){
break 2;
}
}
$removeBottom += 1;
}
$cropped = imagecreatetruecolor(imagesx($jpg) - ($removeLeft + $removeRight), imagesy($jpg) - ($removeTop + $removeBottom));
imagecopy($cropped, $jpg, 0, 0, $removeLeft, $removeTop, imagesx($cropped), imagesy($cropped));
header("Content-type: image/jpeg");
imagejpeg($cropped); //change to `imagejpeg($cropped, $image_path);` to save
imagedestroy($cropped);
imagedestroy($jpg);

Walk an image faster

I need to find a particular pixel of an image. Let's say "89 21 24".
I'm using two nested cycles to walk the image:
for( $y=$inity; $y<$h; $y++) {
for( $x=$initx; $x<$w; $x++) {
$pixel = getpixelat($img,$x,$y);
if ($pixel == "892124" and getpixelat($img,$x+1,$y) == "1212224") {
$px = $x; $py = $y;
break 2;
}
}
I'd like to have a faster algorithm by increasing $y and $x not one by one, instead for example 4 by 4. (Sixteen times faster?)
Of course I need to know exactly the pixels that build 4x4 square.
I would do it like:
if ($pixel == "" and nextpixel...) {
$px = $x - 1; $py = $y -...;
}
//etc.
Is there a smarter way to achieve that?
EDIT:
Here's the getpixelat function:
function getpixelat($img,$x,$y) {
$rgb = imagecolorat($img,$x,$y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
return $r.$g.$b;
}
If you know that the color you are looking for always appears in patches of at least 2x2, or 3x3, or any fixed size, then yes, you can speed up the lookup by incrementing $x and $y by more than one at each iteration.
For instance, if you know that your patches are always of size at least KxL, you can do the following:
for( $y=$inity; $y<$h; $y += L) {
for( $x=$initx; $x<$w; $x += K) {
$pixel = getpixelat($img,$x,$y);
if ($pixel == "892124" and getpixelat($img,$x+1,$y) == "1212224") {
$px = $x; $py = $y;
break 2;
}
}
}
1.) avoide nested loops:
2.) save old value of pixle (calling an function is not that fast)
3.) dont convert colors to string/dont compare strings! (what is 1212224? it is not a Hex-Color )
$px=-1;
$py=-1;
$lineW = ($w-$initx);
$lineH = ($h-$inity);
$count = $lineW * $lineH;
$color1 =hexdec ("892124") ;
$color2 =hexdec ("1212224") ;
$x=$initx;
$y=$inity;
$new = imagecolorat($img,$x,$y);
while(true) {
$x++;
if ($x>=$w) {
$x=$initx+1;
$y++;
if ($y>=$h) break;
$new = imagecolorat($img,$x-1,$y);
}
$old = $new;
$new = imagecolorat($img,$x,$y);
if ($old == $color1 && $new == $color2)
{
$px = $x; $py = $y;
break;
}
}
(code is not tested :-) )

Categories