Trying to convert the following PHP function to Python but getting the following error. What would be the working Python equivalent to the below PHP function?
line 140, in doDetectBigToSmall
for scale in xrange(start_scale, scale > 1,scale = scale* scale_update):
UnboundLocalError: local variable 'scale' referenced before assignment
PHP CODE:
protected function doDetectBigToSmall($ii, $ii2, $width, $height)
{
$s_w = $width/20.0;
$s_h = $height/20.0;
$start_scale = $s_h < $s_w ? $s_h : $s_w;
$scale_update = 1 / 1.2;
for ($scale = $start_scale; $scale > 1; $scale *= $scale_update) {
$w = (20*$scale) >> 0;
$endx = $width - $w - 1;
$endy = $height - $w - 1;
$step = max($scale, 2) >> 0;
$inv_area = 1 / ($w*$w);
for ($y = 0; $y < $endy; $y += $step) {
for ($x = 0; $x < $endx; $x += $step) {
$passed = $this->detectOnSubImage($x, $y, $scale, $ii, $ii2, $w, $width+1, $inv_area);
if ($passed) {
return array('x'=>$x, 'y'=>$y, 'w'=>$w);
}
} // end x
} // end y
} // end scale
return null;
}
PYTHON CODE:
def doDetectBigToSmall(self,ii, ii2, width, height):
s_w = width/20.0
s_h = height/20.0
start_scale = s_h if s_h < s_w else s_w
scale_update = 1 / 1.2
for scale in xrange(start_scale, scale > 1,scale = scale* scale_update):
w = (20*scale) >> 0
endx = width - w - 1
endy = height - w - 1
step = max(scale, 2) >> 0
inv_area = 1 / (w*w)
for y in xrange(0,y < endy,y = y + step):
for x in xrange(0, x < endx, x= x + step):
passed = self.detectOnSubImage(x, y, scale, ii, ii2, w, width+1, inv_area)
if (passed):
return {'x': x, 'y': y, 'w': w}
You have no idea what xrange() does ;-) So read the docs before you try it again. In the meantime, replace:
for scale in xrange(start_scale, scale > 1,scale = scale* scale_update):
with
scale = start_scale
while scale > 1:
and, at the end of the loop, add:
scale *= scale_update
All your other uses of xrange() are similarly broken, but you have to make some effort to learn what it does.
This works for me:
def strpos_r(haystack, needle):
positions = []
position = haystack.rfind(needle)
while position != -1:
positions.append(position)
haystack = haystack[:position]
position = haystack.rfind(needle)
return positions
Also, functions should not really handle input errors for you. You usually just return False or let the function throw an execution error.
This is happening because xrange is a function and you are passing an uninitialized value to it. Scale will not be initialized until after xrange is run and returns a value. Python generally used for loops to iterate over lists. I recommend rewriting your code using while loops.
Related
I need to convert a lot of x/y pixel coordinates from polygon segments (680x680) to the grid references (68x68) the polygon contains.
e.g grid references
1, 2, 3, 4
5, 6, 7, 8
9,10,11,12 etc
Performance is the ultimate goal. My working script does the job however with thousands of sets of polygon segments each minute I'm looking to improve speed further. Currently I'm using the GD library to draw a polygon, then with help of a bounding box, testing the brightness of each polygon pixel to get x/y coordinates, then finally converting those to a grid reference.
While the overhead of generating an image in memory isn't huge, there must be a better (or faster) way to do this.
Working example with output
$p = [];
$r = [];
$p['segments'] = [[144, 637], [225, 516], [85, 460], [30, 482]];
$r = segments_to_grid($p, $r);
print_r($r['grid']);
Array
(
[0] => 3133
[1] => 3134
[2] => 3135
[3] => 3136
[4] => 3137
[5] => 3138
[6] => 3199
[7] => 3200
...
...
[157] => 4092
[158] => 4093
[159] => 4094
[160] => 4095
[161] => 4161
[162] => 4162
[163] => 4229
)
Supporting functions
/**
* Convert a list of x/y coordinates to grid references
*
* #param array $p
* #param array $r
*
* #return array augmented $r
*/
function segments_to_grid($p, $r) {
$p['segments'] = isset($p['segments']) ? $p['segments'] : [];
// e.g, [[144,637],[225,516],[85,460],[30,482]]
// Return array
$r['grid'] = [];
// Define base dimensions
$w = 680;
$h = 680;
$poly_coords = [];
$min_x = $min_y = 680;
$max_x = $max_y = 0;
// Build an imagefilledpolygon compatible array and extract minimum and maximum for bounding box
foreach ($p['segments'] as $segment) {
$poly_coords[] = $segment[0];
$poly_coords[] = $segment[1];
$min_x = min($min_x, $segment[0]);
$min_y = min($min_y, $segment[1]);
$max_x = max($max_x, $segment[0]);
$max_y = max($max_y, $segment[1]);
}
// check we have something useful
if (!empty($poly_coords)) {
$r['code'] = 40;
// create image
$img = imagecreatetruecolor($w, $h);
// allocate colors (white background, black polygon)
$bg = imagecolorallocate($img, 255, 255, 255);
$black = imagecolorallocate($img, 0, 0, 0);
// fill the background
imagefilledrectangle($img, 0, 0, $w, $h, $bg);
// draw a polygon
if (imagefilledpolygon($img, $poly_coords, count($p['segments']), $black)) {
$r['code'] = 0;
// loop through the image and find the points that are black
for ($y = $min_y; $y < $max_y; $y = $y + 10) {
for ($x = $min_x; $x < $max_x; $x = $x + 10) {
$rgb = imagecolorat($img, $x, $y);
if (intval($rgb) < 16777215) {
$r['grid'][] = xy6802g68($x, $y);
}
}
}
} else {
$r['error'] = 'poly fail';
$r['code'] = 10;
}
imagedestroy($img);
} else {
$r['error'] = 'no coordinates';
$r['code'] = 20;
}
return ($r);
}
/**
* Converts X/Y 680x680 to 68x68 grid reference number.
*
* #param int $cX pixel x positon
* #param int $cY pixel y positon
* #return int grid reference number
*/
function xy6802g68($cX, $cY) {
$calcX = ceil($cX / 10) - 1;
$calcY = ceil($cY / 10) - 1;
$grid68 = $calcX + ($calcY * 68);
return ($grid68);
}
Solution thanks to #Oliver's comments.
Porting inpoly to PHP was 168 times faster than using GD image lib.
function segments_to_grid2($p, $r) {
// Define base dimensions
$vertx = $verty = [];
$min_x = $min_y = 680;
$max_x = $max_y = 0;
foreach ($p['segments'] as $segment) {
$vertx[] = $segment[0];
$verty[] = $segment[1];
$min_x = min($min_x, $segment[0]);
$min_y = min($min_y, $segment[1]);
$max_x = max($max_x, $segment[0]);
$max_y = max($max_y, $segment[1]);
}
if (!empty($vertx)) {
$nvert = count($vertx);
for ($y = $min_y; $y < $max_y; $y = $y + 10) {
for ($x = $min_x; $x < $max_x; $x = $x + 10) {
if (inpoly($nvert, $vertx, $verty, $x, $y)) {
$r['grid'][] = xy6802g68($x, $y);
}
}
}
}
return $r;
}
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;
}
Running this 100 times
GD library version:
[segments_to_grid] => 0.0027089119 seconds
inpoly version
[segments_to_grid2] => 0.0001449585 seconds
168 times faster and equivalent output
Thanks Oliver!
Testing if a point lies inside a polygon is a well-known problem.
The classical solution is an algorithm called "ray casting":
Start from the point
Cast a ray in some arbitrary direction and count the number of times it crosses a polygon segment
The parity of the number gives the result (odd: inside; even: outside)
A C implementation of the algorithm is given here:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int 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;
}
A possible PHP version is:
function pnpoly($nvert, $vertx, $verty, $testx, $testy) {
$c = false;
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 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;
}
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).
Hello fellow earthlings. A quesion about RGB color and its usefulness in a simple tiny php code:
Imagine I have variable $colorA containning a valid six char color. say B1B100, a greenish natural color. Now If I would like to make a new color from that, which is, say, ten steps lighter thatn that original color, roughly.
$colorA = B1B100 // original color
php code with little color engine lightening stuff up goes here
$colorB = ?????? // original color lightened up
Is there a php ready function that KNOWS rgb colors something like
php function RGB ( input color, what to do, output color)
Where what to do could be +/- 255 values of brightness etc etc.
Is something like this already possible or am I day dreaming?
rgb-hsl($colorA, +10, $colorB);
If this does not exist, what would be the shortest code for doing this? Suggestions, code or ideas are all answers to me. Thanks.
This SO question has a full-blown PHP script that can convert a RGB to a HSL colour, and increase its H component of a HSL colour - it should be trivial to change to increase L instead.
In general if you want a lighter shade of a particular colour, the most accurate process is to convert from RGB to HSL (or HSV), change the 'L' (or 'V') value which represents lightness, and then convert back to RGB.
This will preserve the "hue", which represents where the colour sits on the spectrum, but change the "tint" (if lightening) or "shade" (if darkening) of that colour.
See http://en.wikipedia.org/wiki/HSL_and_HSV for more information.
On this website: http://www.sitepoint.com/forums/showthread.php?t=586223 they are talking about this code which is originally made by opensource Drupal. Seems to work fine in PHP!?
Now, how do I now indermingle myself with this code and change the lightness of an HSL value, before its outputted as RGB again?
<?php
### RGB >> HSL
function _color_rgb2hsl($rgb) {
$r = $rgb[0]; $g = $rgb[1]; $b = $rgb[2];
$min = min($r, min($g, $b)); $max = max($r, max($g, $b));
$delta = $max - $min; $l = ($min + $max) / 2; $s = 0;
if ($l > 0 && $l < 1) {
$s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
}
$h = 0;
if ($delta > 0) {
if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
$h /= 6;
} return array($h, $s, $l);
}
### HSL >> RGB
function _color_hsl2rgb($hsl) {
$h = $hsl[0]; $s = $hsl[1]; $l = $hsl[2];
$m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
$m1 = $l * 2 - $m2;
return array(_color_hue2rgb($m1, $m2, $h + 0.33333),
_color_hue2rgb($m1, $m2, $h),
_color_hue2rgb($m1, $m2, $h - 0.33333));
}
### Helper function for _color_hsl2rgb().
function _color_hue2rgb($m1, $m2, $h) {
$h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
if ($h * 2 < 1) return $m2;
if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
return $m1;
}
### Convert a hex color into an RGB triplet.
function _color_unpack($hex, $normalize = false) {
if (strlen($hex) == 4) {
$hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
} $c = hexdec($hex);
for ($i = 16; $i >= 0; $i -= 8) {
$out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
} return $out;
}
### Convert an RGB triplet to a hex color.
function _color_pack($rgb, $normalize = false) {
foreach ($rgb as $k => $v) {
$out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
}return '#'. str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
}
/* $testrgb = array(0.2,0.75,0.4); //RGB to start with
print_r($testrgb); */
print "Hex: ";
$testhex = "#b7b700";
print $testhex;
$testhex2rgb = _color_unpack($testhex,true);
print "<br />RGB: ";
var_dump($testhex2rgb);
print "<br />HSL color module: ";
$testrgb2hsl = _color_rgb2hsl($testhex2rgb); //Converteren naar HSL
var_dump($testrgb2hsl);
print "<br />RGB: ";
$testhsl2rgb = _color_hsl2rgb($testrgb2hsl); // En weer terug naar RGB
var_dump($testhsl2rgb);
print "<br />Hex: ";
$testrgb2hex = _color_pack($testhsl2rgb,true);
var_dump($testrgb2hex);
?>
PHP does have a couple image manipulation libraries. Either GD or Imagemagick
EDIT: I jumped the gun, these libraries do not have direct PHP color manipulation functions - I honestly assumed they did of a sort after seeing a lot of the things they can do with images via PHP. They do accomplish a lot of cool things. Here's one guy's example.
For a while now I've been interested in fractals, the math behind them and the visuals they can produce.
I just can't really figure out how to map the mathematical formula to a piece of code that draws the picture.
Given this formula for the mandelbrot set: Pc(z) = z * z + c
How does that compare to the following code:
$outer_adder = ($MaxIm - $MinIm) / $Lines;
$inner_adder = ($MaxRe - $MinRe) / $Cols;
for($Im = $MinIm; $Im <= $MaxIm; $Im += $outer_adder)
{
$x=0;
for($Re = $MinRe; $Re <= $MaxRe; $Re += $inner_adder)
{
$zr = $Re;
$zi = $Im;
for($n = 0; $n < $MaxIter; ++$n)
{
$a = $zr * $zr;
$b = $zi * $zi;
if($a + $b > 2) break;
$zi = 2 * $zr * $zi + $Im;
$zr = $a - $b + $Re;
}
$n = ($n >= $MaxIter ? $MaxIter - 1 : $n);
ImageFilledRectangle($img, $x, $y, $x, $y, $c[$n]);
++$x;
}
++$y;
}
Code is not complete, just showing the main iteration part for brevity.
So the question is: could someone explain to me how the math compares to the code?
Edit: To be clear, I've found dozens of resources explaining the math, and dozens of resources showing code, but nowhere can I find a good explanation of the two combined.
Disclaimer. I didn't know anything about fractals before, but always wanted to know, so I've read the wikipedia article and decided to write what I've found here.
As they say, if you want to understand something, try explaining it to someone else. ;)
Okay, we're going to operate on complex numbers. A complex number is actually a pair of (real) numbers, so, for us php programmers, let it be a two-elements array.
/// Construct a complex number from two reals
function cpl($re, $im) {
return array($re, $im);
}
Now we need to tell php how to do arithmetics on our complex numbers. We'll need addition, multiplication and the mod ("norm") operator. (see http://mathworld.wolfram.com/topics/ComplexNumbers.html for more details).
/// Add two complex numbers.
function cadd($p, $q) {
return cpl(
$p[0] + $q[0],
$p[1] + $q[1]);
}
/// Multiply two complex numbers.
function cmul($p, $q) {
return cpl(
$p[0] * $q[0] - $p[1] * $q[1],
$p[0] * $q[1] + $p[1] * $q[0]);
}
/// Return the norm of the complex number.
function cmod($p) {
return sqrt($p[0] * $p[0] + $p[1] * $p[1]);
}
Now we write a function that returns true if the given (complex) point $c belongs to the mandelbrot set
A point c belongs to the set if all points z = z^2 + c lie inside the circle with the radius 2.
We start with the complex number z = (0, 0).
On each step we calculate z = z * z + c.
If modulus of z > 2 - that is, we're out of the circle - the point is NOT in set
Otherwise repeat the step.
To prevent that from looping endlessly, limit the max number of iterations.
function is_in_mandelbrot_set($c, $iterations) {
$z = cpl(0, 0);
do {
if(cmod($z) >= 2)
return false;
$z = cadd(cmul($z, $z), $c);
} while($iterations--);
return true;
}
The rest has nothing to do with math and is quite obvious
function mandelbrot($img, $w, $h) {
$color = imagecolorallocate($img, 0xFF, 0, 0);
$zoom = 50;
$iters = 30;
for($x = 0; $x < $w; $x++) {
for($y = 0; $y < $h; $y++) {
// scale our integer points
// to be small real numbers around 0
$px = ($x - $w / 2) / $zoom;
$py = ($y - $h / 2) / $zoom;
$c = cpl($px, $py);
if(is_in_mandelbrot_set($c, $iters))
imagesetpixel($img, $x, $y, $color);
}
}
return $img;
}
$w = 200;
$h = 200;
header("Content-type: image/png");
imagepng(
mandelbrot(
imagecreatetruecolor($w, $h), $w, $h));
Result
Of course, this code is ineffective to the extreme. Its only purpose is to understand the math concept.