Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace the specific RGB color with another image using PHP

I derived a perfect color replace script from https://stackoverflow.com/a/32710756/1620626. I want to replace the target color with the image background. The original image is backgrounded with light green (rgb:0b255b1). I can replace it with blue but I don't have an idea how to replace with the image. Here's the script.

This is the original image. 01.jpg

Once I process this photo with the script. I've got this. enter image description here

The script is perfectly replace the target color with the new one. Now I want to change from blue into the background. So the final idea is. This girl on the background image I chosen.

Here is the code:

<?php
//https://stackoverflow.com/a/32710756/1620626
function RGBtoHSL( $r, $g, $b ) {
    $r /= 255;
    $g /= 255;
    $b /= 255;
    $max = max( $r, $g, $b );
    $min = min( $r, $g, $b );
    $l = ( $max + $min ) / 2;
    $d = $max - $min;
    if( $d == 0 ){
        $h = $s = 0;
    } else {
        $s = $d / ( 1 - abs( 2 * $l - 1 ) );
        switch( $max ){
            case $r:
                $h = 60 * fmod( ( ( $g - $b ) / $d ), 6 );
                if ($b > $g) {
                    $h += 360;
                }
                break;
            case $g:
                $h = 60 * ( ( $b - $r ) / $d + 2 );
                break;
            case $b:
                $h = 60 * ( ( $r - $g ) / $d + 4 );
                break;
        }
    }
    return array( round( $h, 2 ), round( $s, 2 ), round( $l, 2 ) );
}

function HSLtoRGB( $h, $s, $l ){
    $c = ( 1 - abs( 2 * $l - 1 ) ) * $s;
    $x = $c * ( 1 - abs( fmod( ( $h / 60 ), 2 ) - 1 ) );
    $m = $l - ( $c / 2 );
    if ( $h < 60 ) {
        $r = $c;
        $g = $x;
        $b = 0;
    } else if ( $h < 120 ) {
        $r = $x;
        $g = $c;
        $b = 0;
    } else if ( $h < 180 ) {
        $r = 0;
        $g = $c;
        $b = $x;
    } else if ( $h < 240 ) {
        $r = 0;
        $g = $x;
        $b = $c;
    } else if ( $h < 300 ) {
        $r = $x;
        $g = 0;
        $b = $c;
    } else {
        $r = $c;
        $g = 0;
        $b = $x;
    }
    $r = ( $r + $m ) * 255;
    $g = ( $g + $m ) * 255;
    $b = ( $b + $m  ) * 255;
    return array( floor( $r ), floor( $g ), floor( $b ) );
}

/* ---------------CHANGE THESE------------------- */
$colorToReplace = RGBtoHSL(0,255,1);//target color
$hueAbsoluteError = 7;//the more the clearer
$replacementColor = RGBtoHSL(0, 192, 239);//new color
/* ---------------------------------------------- */

$filename = 'images/01.png';
$im = imagecreatefrompng($filename);
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
$transColor = imagecolorallocatealpha($out, 254, 254, 254, 127);
imagefill($out, 0, 0, $transColor);

for ($x = 0; $x < imagesx($im); $x++) {
    for ($y = 0; $y < imagesy($im); $y++) {
        $pixel = imagecolorat($im, $x, $y);

        $red = ($pixel >> 16) & 0xFF;
        $green = ($pixel >> 8) & 0xFF;
        $blue = $pixel & 0xFF;
        $alpha = ($pixel & 0x7F000000) >> 24;

        $colorHSL = RGBtoHSL($red, $green, $blue);

        if ((($colorHSL[0]  >= $colorToReplace[0] - $hueAbsoluteError) && ($colorToReplace[0] + $hueAbsoluteError) >= $colorHSL[0])){
            $color = HSLtoRGB($replacementColor[0], $replacementColor[1], $colorHSL[2]);
            $red = $color[0];
            $green= $color[1];
            $blue = $color[2];
        }

        if ($alpha == 127) {
            imagesetpixel($out, $x, $y, $transColor);
        }
        else {
            imagesetpixel($out, $x, $y, imagecolorallocatealpha($out, $red, $green, $blue, $alpha));
        }
    }
}
imagecolortransparent($out, $transColor);
imagesavealpha($out, TRUE);
header('Content-type: image/png');
imagepng($out);
?> 
like image 825
Wilf Avatar asked Jan 22 '16 10:01

Wilf


1 Answers

You can just read two images, source and background, and take pixels from background image and set to the source.

Below is the last part of your code above which shows this idea:

$filename = 'images/01.png';
$bgFilename = 'images/background.png';
$im = imagecreatefrompng($filename);
$bg = imagecreatefrompng($bgFilename);
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
$transColor = imagecolorallocatealpha($out, 254, 254, 254, 127);
imagefill($out, 0, 0, $transColor);

for ($x = 0; $x < imagesx($im); $x++) {
    for ($y = 0; $y < imagesy($im); $y++) {
        $pixel = imagecolorat($im, $x, $y);
        $bgPixel = imagecolorat($bg, $x, $y);

        $red = ($pixel >> 16) & 0xFF;
        $green = ($pixel >> 8) & 0xFF;
        $blue = $pixel & 0xFF;
        $alpha = ($pixel & 0x7F000000) >> 24;
        $colorHSL = RGBtoHSL($red, $green, $blue);

        if ((($colorHSL[0]  >= $colorToReplace[0] - $hueAbsoluteError) && ($colorToReplace[0] + $hueAbsoluteError) >= $colorHSL[0])){
            // Instead of taking the replacementColor
            /* $color = HSLtoRGB($replacementColor[0], $replacementColor[1], $colorHSL[2]); */
            /* $red = $color[0]; */
            /* $green= $color[1]; */
            /* $blue = $color[2]; */
            // We just take colors from the backround image pixel
            $red = ($bgPixel >> 16) & 0xFF;
            $green = ($bgPixel >> 8) & 0xFF;
            $blue = $bgPixel & 0xFF;
        }

        if ($alpha == 127) {
            imagesetpixel($out, $x, $y, $transColor);
        }
        else {
            imagesetpixel($out, $x, $y, imagecolorallocatealpha($out, $red, $green, $blue, $alpha));
        }
    }
}
imagecolortransparent($out, $transColor);
imagesavealpha($out, TRUE);
header('Content-type: image/png');
imagepng($out);

The result can look like this:

enter image description here

like image 93
Boris Serebrov Avatar answered Nov 18 '22 18:11

Boris Serebrov