Transformacja zdjęcia PHP - efekt zimna

0

Witam

Potrzebuję przerobić obrazek (jpg) w taki sposób, żeby otrzymać efekt zimna. Działanie jest takie, że użytkownik dodaje zdjęcia, robię upload i w tedy w zależności od ustawień dodaję różne efekty do zdjęcia, np.: robię zdjęcie czarno-białe. Potrzebuję dodać nowy efekt, o który upominało się kilku użytkowników ale nie wychodzi mi to tak jak bym chciał, tzn. kolory mojego 'zimnego' efektu są kiepskie i niezgodne z oczekiwaniami. Dla przykładu podam linki do dwóch przykładowych zdjęć, oryginał i z tym efektem:
http://zapodaj.net/f46261f6ebd6.jpg.html - oryginał
http://zapodaj.net/6d3c3076b676.jpg.html - z efektem cold

To zdjęcie z efektem to jest coś co chciałbym osiągnąć. Zwykłe kolorowanie zdjęcia wydaje się być niewystarczające ponieważ wykorzystałem różne kombinacje RGB i żaden nie dał takiego efektu. Prawda jest taka, że po prostu nie do końca wiem jak się za to zabrać, w jaki sposób osiągnąć taki efekt. Takie dodanie efektu samo w sobie nie jest skomplikowane - o ile się wie co trzeba zrobić - więc mam nadzieję, że ktoś mi pomoże. Z góry dzięki :)

0

Spróbuj zamienić kanał luminancji na wartość kanału niebieskiego przy jednoczesnym wyzerowaniu kanałów zielonego i czerwonego.
Przyda Ci się konwersja na HLS by uzyskać luminancję (kanał L).

0

Dzięki za odpowiedź.

Znalazłem w sieci gotowe skrypty na konwersję z rgb na hsl:

 
function rgb2hsl($rgb){
   
     $clrR = ($rgb[0] / 255);
     $clrG = ($rgb[1] / 255);
     $clrB = ($rgb[2] / 255);
   
     $clrMin = min($clrR, $clrG, $clrB);
     $clrMax = max($clrR, $clrG, $clrB);
     $deltaMax = $clrMax - $clrMin;
   
     $L = ($clrMax + $clrMin) / 2;
   
     if (0 == $deltaMax){
         $H = 0;
         $S = 0;
         }
    else{
         if (0.5 > $L){
             $S = $deltaMax / ($clrMax + $clrMin);
             }
        else{
             $S = $deltaMax / (2 - $clrMax - $clrMin);
             }
         $deltaR = ((($clrMax - $clrR) / 6) + ($deltaMax / 2)) / $deltaMax;
         $deltaG = ((($clrMax - $clrG) / 6) + ($deltaMax / 2)) / $deltaMax;
         $deltaB = ((($clrMax - $clrB) / 6) + ($deltaMax / 2)) / $deltaMax;
         if ($clrR == $clrMax){
             $H = $deltaB - $deltaG;
             }
        else if ($clrG == $clrMax){
             $H = (1 / 3) + $deltaR - $deltaB;
             }
        else if ($clrB == $clrMax){
             $H = (2 / 3) + $deltaG - $deltaR;
             }
         if (0 > $H) $H += 1;
         if (1 < $H) $H -= 1;
         }
     return array($H, $S, $L);
}

rzecz w tym, że nie wiem jak do tego podejść. Jeżeli wiesz jak powinna wyglądać reszta kodu to proszę napisz bo motam się i nie wiem co źle robię. Czyli tak:
Wczytujemy i tworzymy zdjęcie:

$img = imagecreatefromjpeg($url);

przekształcamy zdjęcie z rgb na hsl i dodajemy efekt zimna.... TUTAJ POTRZEBNA POMOC
a potem reszta:

$jpeg_quality = 100;
header('Content-type: image/jpeg');
imagejpeg($img,null,$jpeg_quality);
0

To jest przykładowy kod. Nie jest zoptymalizowany - raczej jako proof of concept. Nie odtworzyłem też dokładnie tego efektu bo nie znam tamtego algorytmu. Możesz sam go zmienić bawiąc się zarówno wartościami RGB jak i HSL - wedle zapotrzebowania. Nie jest powiedziane, że musisz zamieniać na HSL ale to był mój pierwszy strzał bo łatwiej manipulować HSL niż RGB.

<?php
function rgb2hsl($rgb) {
	$clrR = ($rgb[0] / 255);
	$clrG = ($rgb[1] / 255);
	$clrB = ($rgb[2] / 255);

	$clrMin = min($clrR, $clrG, $clrB);
	$clrMax = max($clrR, $clrG, $clrB);
	$deltaMax = $clrMax - $clrMin;

	$L = ($clrMax + $clrMin) / 2;

	if (0 == $deltaMax) {
		$H = 0;
		$S = 0;
	} else {
		if (0.5 > $L) {
			$S = $deltaMax / ($clrMax + $clrMin);
		} else {
			$S = $deltaMax / (2 - $clrMax - $clrMin);
		}
		$deltaR = ((($clrMax - $clrR) / 6) + ($deltaMax / 2)) / $deltaMax;
		$deltaG = ((($clrMax - $clrG) / 6) + ($deltaMax / 2)) / $deltaMax;
		$deltaB = ((($clrMax - $clrB) / 6) + ($deltaMax / 2)) / $deltaMax;
		if ($clrR == $clrMax) {
			$H = $deltaB - $deltaG;
		} else if ($clrG == $clrMax) {
			$H = (1 / 3) + $deltaR - $deltaB;
		} else if ($clrB == $clrMax) {
			$H = (2 / 3) + $deltaG - $deltaR;
		}
		if (0 > $H) $H += 1;
		if (1 < $H) $H -= 1;
	}
	return array($H, $S, $L);
}

function hue($base, $m1, $m2) {
	$base = ( $base < 0 ) ? $base + 1 : ( ( $base > 1 ) ? $base - 1 : $base );
	if ( $base * 6 < 1 ) return $m1 + ( $m2 - $m1 ) * $base * 6;
	if ( $base * 2 < 1 ) return $m2;
	if ( $base * 3 < 2 ) return $m1 + ( $m2 - $m1 ) * ( 0.66666 - $base ) * 6;
	return $m1;
}

function 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( hue( $h + 0.33333, $m1, $m2 ), hue( $h, $m1, $m2 ), hue( $h - 0.33333, $m1, $m2 ) );
} 

//otworzenie obrazka
$img = imagecreatefromjpeg('pic.jpg');

//pobranie rozmiaru
$w = imagesx( $img );
$h = imagesy( $img );

for( $x = 0; $x < $w; $x++ ) {
	for( $y = 0; $y < $h; $y++ ) {
		//pobraine RGB
		$rgb = imagecolorat($img, $x, $y);
		//wyjęcie RGB do zmiennych
		$r = ($rgb >> 16) & 0xFF;
		$g = ($rgb >> 8) & 0xFF;
		$b = $rgb & 0xFF;
		//przerobienie na skalę szarości
		$gray = 0.21 * $r + 0.71 * $g + 0.07 * $b;
		//zamiana na hsl
		$hsl = rgb2hsl(array($gray, $gray, $gray));
		//zmiana koloru (hue) na okolice niebieskiego
		$hsl[0] = 150 / 255;
		//podbicie nasycenie (saturation) (było 0 bo przerobiliśmy obraz na skalę szarości)
		$hsl[1] = 0.5;
		//jasność (luminosity) zostawiamy w spokoju
		//powrót do RGB
		$rgb = hsl2rgb($hsl);
		//zamiana 0..1 na 0..255
		$rgb[0] = round(255 * $rgb[0]);
		$rgb[1] = round(255 * $rgb[1]);
		$rgb[2] = round(255 * $rgb[2]);
		//zamiana na integer
		$color =
			((($rgb[0]) & 0xff) << 16) |
			((($rgb[1]) & 0xff) << 8) |
			(($rgb[2]) & 0xff);
		//ustawienie koloru
		imagesetpixel($img, $x, $y,$color);
	}
}

//wyplucie obrazu do przeglądarki
$jpeg_quality = 100;
header('Content-type: image/jpeg');
imagejpeg($img, null, $jpeg_quality);

//zwolnienie pamięci
imagedestroy($img);

1 użytkowników online, w tym zalogowanych: 0, gości: 1