// Persistence of Vision Ray Tracer version 3.7 // Scene Description Language (SDL) // File: HexagonalColorHistogram.pov // Version: 1.0 // Last updated: 19-Mar-2017 // Description: Creates histogram of RGB colors in image file for use in color map development // // Author: Bill Walker "Bald Eagle", 2017 // email: see posts in news.povray.org // //------------------------------------------------------------------------ #version 3.7; global_settings {assumed_gamma 1.0} //****************************************************************** #declare ImageFile = pigment {image_map {jpeg "Frog.jpg"}}; // Set threshold to zero to see full list of discretized color values // Set threshold to remove minor contributing colors from color map // See scene ouput in Message pane for list of colors and levels #declare Threshold = 0; //****************************************************************** #include "colors.inc" #include "textures.inc" #include "transforms.inc" #declare Camera_Position = < 0, 0, -50.0>; #declare Camera_Look_At = < 0, 0, 0.00>; camera {location Camera_Position right x*image_width/image_height look_at Camera_Look_At } #declare Feet = 12; light_source {<2*Feet, 6*Feet, -10*Feet> color rgb <1, 1, 1> shadowless} sky_sphere { pigment { gradient <0,1,0> color_map { [0 color rgb <1, 1, 1>*0.5] // White [0.4 color rgb <1, 1, 1>*0.0] // Black [0.6 color rgb <1, 1, 1>*0.0] // Black [1.0 color rgb <1, 1, 1>*0.5] // White } // end color map scale 2 } // end pigment } // end sky_sphere #declare Resolution = max_extent (ImageFile); #declare PictureScale = ; #declare Scale = 10; // define basis vectors #declare G = <0, 1, 0>; #declare R = vtransform (G, transform {rotate z*120}); #declare B = vtransform (G, transform {rotate -z*120}); // Show color space hexagon with full RGB gamut //======================================================================================================================= union { /* union { cylinder {R, R+G, 0.1/Scale} cylinder {R+G, G 0.1/Scale} cylinder {G, G+B, 0.1/Scale} cylinder {G+B, B, 0.1/Scale} cylinder {B, B+R, 0.1/Scale} cylinder {B+R, R, 0.1/Scale} scale Scale pigment {Black} } union { cylinder {0, R, 0.1/Scale pigment {Red}} cylinder {0, G, 0.1/Scale pigment {Green}} cylinder {0, B, 0.1/Scale pigment {Blue}} scale Scale } */ #declare Step = 0.02; #declare S = Step/2; #declare SN = pow ((1/Step), 3); #debug concat ("[Top Left] - Plotting Finely discretized RGB gamut with ", str (SN, 7, 0), " spheres \n\n") #for (BB, S, 1, Step) #for (GG, S, 1, Step) #for (RR, S, 1, Step) #declare Color = ; sphere {(Color.red*R + Color.green*G + Color.blue*B)*Scale ((Step/2)*Scale) pigment {rgb Color} translate z*((Color.red + Color.green + Color.blue)/3)} #end // end for RR #end // end for GG #end // end for BB text { ttf "arial.ttf", " RGB gamut (fine)", 0.02, 0.0 // thickness, offset pigment {Black} scale 2 translate y*Scale*0.75 translate -x*(Scale) translate -z*Scale } // end of text translate -x*Scale translate y*Scale } //======================================================================================================================= // create a hexagonal array of 2D endpoints #declare Step = 0.2; #declare S = Step/2; #declare SN = pow ((1/Step), 2); #debug concat ("[Bottom Left] - Plotting Roughly Discretized RGB gamut with ", str (SN*3, 7, 0), " spheres \n\n") // zero out accumulator array #declare D = 1/Step; //#debug concat ("Dimensioning array [3][", str (D, 1, 1), "][", str (D, 1, 1), "] \n") #declare ColorArray = array [3][D][D]; #for (Segment, 0, 2) #for (H, 0, D-1) #for (W, 0, D-1) //#debug concat ("Segment = ", str (Segment, 1, 1), "| H = ", str (H, 1, 1), " | W = ", str (W, 1, 1), " \n") #declare ColorArray[Segment][H][W] = 0; #end #end #end // end for Segment //======================================================================================================================= // plot RGB segments // -------- union { //#debug concat ("Plotting RG gamut with ", str (SN, 7, 0), " spheres \n") #declare BB=0; #for (GG, S, 1, Step) #for (RR, S, 1, Step) #declare Color = ; sphere {(Color.red*R + Color.green*G + Color.blue*B)*Scale ((Step/2)*Scale) pigment {rgb Color} translate z*(((Color.red + Color.green + Color.blue)/3)-1)} #end // end for RR #end // end for GG //#debug concat ("Plotting GB gamut with ", str (SN, 7, 0), " spheres \n") #declare RR=0; #for (GG, S, 1, Step) #for (BB, S, 1, Step) #declare Color = ; sphere {(Color.red*R + Color.green*G + Color.blue*B)*Scale ((Step/2)*Scale) pigment {rgb Color} translate z*(((Color.red + Color.green + Color.blue)/3)-1)} #end // end for RR #end // end for GG //#debug concat ("Plotting BR gamut with ", str (SN, 7, 0), " spheres \n") #declare GG=0; #for (BB, S, 1, Step) #for (RR, S, 1, Step) #declare Color = ; sphere {(Color.red*R + Color.green*G + Color.blue*B)*Scale ((Step/2)*Scale) pigment {rgb Color} translate z*(((Color.red + Color.green + Color.blue)/3)-1)} #end // end for RR #end // end for GG text { ttf "arial.ttf", " RGB gamut (rough)", 0.02, 0.0 // thickness, offset pigment {Black} scale 2 translate -y*Scale*0.75 translate -x*(Scale) translate -z*Scale } // end of text translate -x*Scale translate -y*Scale } // end union //======================================================================================================================= // Sized image Map - 1 unit thick box #declare XSize = Scale; #declare Resolution = max_extent (ImageFile); #declare Resolution = Resolution + <0, 0, 1>; #declare ImageMappedBox = box {0, 1 texture { pigment {ImageFile} } translate <-0.5, -0.5, -0.5> scale Resolution*(1/Resolution.x)*XSize //translate y*(Resolution.y / Resolution.x)*XSize/2 } object {ImageMappedBox translate <0, 0, 0>} //======================================================================================================================= // Show hexagonalized sampling results of selected picture file #declare Line = 0.075; union { union { cylinder {R, R+G, Line/Scale} cylinder {R+G, G Line/Scale} cylinder {G, G+B, Line/Scale} cylinder {G+B, B, Line/Scale} cylinder {B, B+R, Line/Scale} cylinder {B+R, R, Line/Scale} scale Scale pigment {Black} } // end inner union union { cylinder {0, R, Line/Scale pigment {Red}} cylinder {0, G, Line/Scale pigment {Green}} cylinder {0, B, Line/Scale pigment {Blue}} scale Scale } // end inner union #declare Discrete = 0.2; //subdivision of 0-1 r, g, and B color ranges #declare Step = 5; //stepping for X-Y sampling of image. 1 = sample every pixel, 2 = sample every other, etc. #debug concat ("Image file dimensions: ", str (Resolution.x, 5, 0), " x ", str (Resolution.y, 5, 0), " \n") #debug concat ("Reading 1 out of every ", str (Step, 2, 0), " color values from ", str (Resolution.x * Resolution.y, 10, 0), " pixels in image file... \n\n") #debug "[Top Right] - Plotting Full RGB gamut of image file in hexagonal grid... \n\n" #declare Maximum = 0; #for (Y, 0, Resolution.y, Step) #for (X, 0, Resolution.x, Step) #declare Color = eval_pigment (ImageFile, ); sphere {(Color.red*R + Color.green*G + Color.blue*B)*Scale 0.1 pigment {Color} translate z*((Color.red + Color.green + Color.blue)/3)} //#debug concat ( "Vector = ", vstr(3, (Color.red*R + Color.green*G + Color.blue*B), ", ", 3, 0), " \n") //#debug concat ("X = ", str (X, 1, 0), "| Y = ", str (Y, 1, 0), " <", str (Color.red, 3, 3), ", ", str (Color.green, 3, 3), ", ", str (Color.blue, 3, 3), ">\n") #declare _RG = vcross (Color.red*R, Color.green*G); #declare RG = sqrt(pow(_RG.x, 2)+pow(_RG.y, 2)+pow(_RG.z, 2)); #declare _GB = vcross (Color.green*G, Color.blue*B); #declare GB = sqrt(pow(_GB.x, 2)+pow(_GB.y, 2)+pow(_GB.z, 2)); #declare _BR = vcross (Color.blue*B, Color.red*R); #declare BR = sqrt(pow(_BR.x, 2)+pow(_BR.y, 2)+pow(_BR.z, 2)); #if (RG > GB + BR) #declare Segment = 0; #declare _R = int((1/Discrete)*Color.red); #declare _G = int((1/Discrete)*Color.green); #if (_R < 0 | _R > D-1 | _G < 0 | _G > D-1) //#debug concat ("Segment = ", str (Segment, 1, 1), "| _R = ", str (_R, 1, 3), " | _G = ", str (_G, 1, 3), " OUT OF RANGE - REJECTING \n") #else #declare ColorArray[Segment][_R][_G] = ColorArray[Segment][_R][_G] + 1; #declare Maximum = max (Maximum, ColorArray[Segment][_R][_G]); //#debug concat ("Segment = ", str (Segment, 1, 1), "| _R = ", str (_R, 1, 3), " | _G = ", str (_G, 1, 3), " | ", str (ColorArray[Segment][_R][_G], 5, 1), " \n") #end // end inner if #end // end if #if (GB > RG + BR) #declare Segment = 1; #declare _G = int((1/Discrete)*Color.green); #declare _B = int((1/Discrete)*Color.blue); #if (_B < 0 | _B > D-1 | _G < 0 | _G > D-1) //#debug concat ("Segment = ", str (Segment, 1, 1), "| _G = ", str (_G, 1, 3), " | _B = ", str (_B, 1, 3), " OUT OF RANGE - REJECTING \n") #else #declare ColorArray[Segment][_G][_B] = ColorArray[Segment][_G][_B] + 1; #declare Maximum = max (Maximum, ColorArray[Segment][_B][_B]); //#debug concat ("Segment = ", str (Segment, 1, 1), "| _G = ", str (_G, 1, 3), " | _B = ", str (_B, 1, 3), " | ", str (ColorArray[Segment][_G][_B], 5, 1), " \n") #end // end inner if #end // end if #if (BR > RG + GB) #declare Segment = 2; #declare _B = int((1/Discrete)*Color.blue); #declare _R = int((1/Discrete)*Color.red); #if (_B < 0 | _B > D-1 | _R < 0 | _R > D-1) //#debug concat ("Segment = ", str (Segment, 1, 1), "| _R = ", str (_R, 1, 1), " | _B = ", str (_B, 1, 1), " OUT OF RANGE - REJECTING \n") #else #declare ColorArray[Segment][_B][_R] = ColorArray[Segment][_B][_R] + 1; #declare Maximum = max (Maximum, ColorArray[Segment][_B][_R]); //#debug concat ("Segment = ", str (Segment, 1, 1), "| _B = ", str (_B, 1, 3), " | _R = ", str (_R, 1, 3), " | ", str (ColorArray[Segment][_B][_R], 5, 1), " \n") #end // end inner if #end // end if //#debug "\n" #end // end for X #end // end for Y text { ttf "arial.ttf", " Image file (all)", 0.02, 0.0 // thickness, offset pigment {Black} scale 2 translate y*(Scale*0.75) translate -x*Scale translate -z*(Scale) } // end of text translate x*Scale*1.5 translate y*Scale } // end union // display histogram #debug "[Bottom Right] - Displaying roughly discretized (averaged) colors of image file... \n" // plot RGB histogram segments #debug "\n\nCalculated Color Map: \n" #debug "--------------------- \n" union { #declare Segment = 0; #declare BB=0; #for (GG, 0, D-1) #for (RR, 0, D-1) #declare Color = ; #declare _R = RR;//int((1/Discrete)*RR); #declare _G = GG;//int((1/Discrete)*GG); #if (ColorArray[Segment][_R][_G] > 0 & ColorArray[Segment][_R][_G] >= Threshold) cylinder {(Color.red*R + Color.green*G + Color.blue*B)*Scale, ((Color.red*R + Color.green*G + Color.blue*B)*Scale) + <0, 0, -ColorArray[Segment][_R][_G]*(Scale/Maximum)> ((Discrete/2)*Scale) pigment {rgb Color} } #debug concat ( "Average RGB = <", vstr(3, Color, ", ", 0, 2), "> | Level: ", str (ColorArray[Segment][_R][_G], 7, 0), " \n") #end // end if #end // end for RR #end // end for GG #declare Segment = 1; #declare RR=0; #for (GG, 0, D-1) #for (BB, 0, D-1) #declare Color = ; #declare _G = GG;//int((1/Discrete)*GG); #declare _B = BB;//int((1/Discrete)*BB); #if (ColorArray[Segment][_G][_B] > 0 & ColorArray[Segment][_R][_G] >= Threshold) cylinder {(Color.red*R + Color.green*G + Color.blue*B)*Scale, ((Color.red*R + Color.green*G + Color.blue*B)*Scale) + <0, 0, -ColorArray[Segment][_G][_B]*(Scale/Maximum)> ((Discrete/2)*Scale) pigment {rgb Color} } #debug concat ( "Average RGB = <", vstr(3, Color, ", ", 0, 2), "> | Level: ", str (ColorArray[Segment][_G][_B], 7, 0), " \n") #end // end if #end // end for RR #end // end for GG #declare Segment = 2; #declare GG=0; #for (BB, 0, D-1) #for (RR, 0, D-1) #declare Color = ; #declare _B = BB;//int((1/Discrete)*BB); #declare _R = RR;//int((1/Discrete)*RR); #if (ColorArray[Segment][_B][_R] > 0 & ColorArray[Segment][_R][_G] >= Threshold) cylinder {(Color.red*R + Color.green*G + Color.blue*B)*Scale, ((Color.red*R + Color.green*G + Color.blue*B)*Scale) + <0, 0, -ColorArray[Segment][_B][_R]*(Scale/Maximum)> ((Discrete/2)*Scale) pigment {rgb Color} } #debug concat ( "Average RGB = <", vstr(3, Color, ", ", 0, 2), "> | Level: ", str (ColorArray[Segment][_B][_R], 7, 0), " \n") #end // end if #end // end for RR #end // end for GG #debug "--------------------- \n\n" text { ttf "arial.ttf", "Discretized Color Map", 0.02, 0.0 // thickness, offset pigment {Black} scale 2 translate -y*(Scale*0.75) translate -x*Scale translate -z*(Scale) } // end of text translate x*Scale*1.5 translate -y*Scale } // end union