0

After working/studying hours with canvas i have managed to get the image clone and it's pixels now i have made the user select a color from a color specterm and i have that color hex in my function :

move: function (color) {

 // 'color' is the value user selected

var img_id = jQuery(".selected_bg_img").attr("id");

alert(img_id);

var x = 0;
var y = 0;
var width = 409;
var height = 409;


var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById(img_id);
ctx.drawImage(img,x,y,width,height);

var imageData = ctx.getImageData(0,0,width,height);

var data = imageData.data;

alert(data);

}

now two tasks are getting in way,
1. How do we extract the dominant color from data ?
2. How do we convert that dominant color to the color we got in function ? for live working example i have link given at end
NOTE: Select the images (any last 3) from left side of the product image and and when color is choose it clones the image to the canvas.
Here i am trying to clone the image with replacement of maximum color with the color user selected..

for (var i=0;i<imgData.data.length;i+=4)
{
  imgData.data[i]=255-imgData.data[i];
  imgData.data[i+1]=255-imgData.data[i+1];
  imgData.data[i+2]=255-imgData.data[i+2];
  imgData.data[i+3]=255;
  }

*****EDIT*****
My problem is not very complex i think i have this image enter image description here enter image description here
so we can see clearly that the dominant color is grey, by any method i am just trying to replace that color with the new color i have in my function move and draw that image with the new color. The image from where i have taken and shows another example : http://www.art.com/products/p14499522-sa-i3061806/pela-silverman-colorful-season-i.htm?sOrig=CAT&sOrigID=0&dimVals=729271&ui=573414C032AA44A693A641C8164EB595 on left side of image when we select the similar image they have option "change color" at the bottom center of image. This is what exactly i'm trying to do.

So now i tried to read the image 1x1 and this is what i get in the console when i log it(particular for the image i have shown) :

[166, 158, 152, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]

So it maybe the very first start from top left corner, i guess it need to be iterated over whole image and this is what i get when i iterated over whole image:

[110, 118, 124, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255…]

The loop i used for iteration is:

var imageData = ctx.getImageData(0,0,width,height);

var data = imageData.data;

for (var i=0;i<data.length;i+=4)
{
  data[i]=255-data[i];
  data[i+1]=255-data[i+1];
  data[i+2]=255-data[i+2];
  data[i+3]=255;
}
console.log(data);

Is this iteration right ? If yes, it seems to be now counting and replacing the dominant color and i'm blank here but i have now user value in rgb, need to look for places where that value should be placed

Habib Rehman
  • 590
  • 3
  • 15
  • 36
  • 1
    They're using 2 images - one you see and 1 used as a mask. The mask makes selecting the parts to colorize easy. To colorize, simply grab the rgb of a pixel, convert to hsv or hsl then change the hue to the desired one and convert back to rgb. Just do this for each pixel in the source image when the mask isn't transparent. Look at these two images: (colour) http://cache1.artprintimages.com/images/spp/living_61_70.jpg and (trans/white)http://cache1.artprintimages.com/images/spp/living_61_70_mask.png – enhzflep Sep 29 '16 at 11:25
  • @enhzflep Thanks a bunch for telling that and so does my technique flaws, can't we do it this way ? Anyway if they are using mask and if its easy technique i should see this now. any resource to look at how we do mask (mean converting and after converting how do we write it)? – Habib Rehman Sep 29 '16 at 11:30
  • No worries. Well, the problem with detecting the colour automatically is selecting the areas to change. There is a larger variation between some parts of the wall, than there is between parts of the wall and the cushions on the couch. In other cases, an area will be separated by a lamp or something, yet we still need to change the colour of this 'island'. With this in mind, a mask is the easiest, most general solution. Method: for each x,y in the mask, get the mask pixel, if color/transparency right, get same x,y pixel from src img, colorize then put back. – enhzflep Sep 29 '16 at 11:41
  • yes you are right we may get unnecessary pixel changed by the method i'm trying to do. i got the idea behind it now let me dive into the mask method i'll update the question or delete this one and make new one. Thanks again i almost spent 16 hours on just to have a hint for the solution -_ – Habib Rehman Sep 29 '16 at 11:47
  • 1
    @enhzflep could you please take a look at what i have just found: http://stackoverflow.com/questions/18379818/canvas-image-masking-overlapping is this what i'm gonna do ? – Habib Rehman Sep 29 '16 at 11:52
  • 1
    yep, spot on. Damn! I'd forgotten all about the canvas's built-in compositing modes, though I read several tutorials on using them. That answers looks perfect for you. – enhzflep Sep 29 '16 at 11:55
  • 1
    If you have access to the original RAW (from camera HDRI) creating a mask automatically will be a lot simplier. JPJ compression gets most of its size reduction by reducing the colour component. This makes them almost impossible to process when you want fine colour selection. I have never seen a way to replace a colour in a JPG that works well, you will always get bleeding. Your only option is to create the mask manually or tint the whole image. – Blindman67 Sep 29 '16 at 15:18
  • @enhzflep hey there, need help i'm still stuck in that wall thingy i get dispersed color over image – Habib Rehman Oct 06 '16 at 14:05
  • @HabibRehman - hia, chuck me a link to your code somewhere and I'll have a look if you like. jsfiddle is fine, so's pastebin (where you can set an expiry time) – enhzflep Oct 06 '16 at 14:36
  • @enhzflep okay let me do that i'll paste link here – Habib Rehman Oct 06 '16 at 14:45
  • @enhzflep check this code https://jsfiddle.net/vh2wLx26/#&togetherjs=OovrIwrB3w – Habib Rehman Oct 06 '16 at 14:55
  • it's a real time collaborator – Habib Rehman Oct 06 '16 at 14:56
  • Okay, got the link. Sorry, I don't do skype/messenger or anything else that performs the same function. Hope you understand and don't take offence. – enhzflep Oct 06 '16 at 14:59
  • okay actually i'm not familiar working with jsfiddle, sorry for that they only way i get the link to share fiddle was this. and i didn't gave it for skype/messager it was a real collaborator (just in case if you think that) – Habib Rehman Oct 06 '16 at 15:01
  • @HabibRehman - no problem, I made no assumptions at all (that I'm aware of!) Trackpad went funny so had to reboot (first time in a month!) - I'm just getting started into the code now and will let you know how I get on. :) – enhzflep Oct 06 '16 at 15:35
  • thanks in advance, i tried to implement it with the js spectrum in fiddle but don't know fiddle is going crazy over that. – Habib Rehman Oct 06 '16 at 15:36
  • getting bit/an inch closer, i used the property overly it tends to now change whole color of image still not drawing it correctly and my image of wall is getting in way too, but i'm still not making sense – Habib Rehman Oct 06 '16 at 16:21

1 Answers1

3

Here you go. It looks like I gave bad and misleading information earlier when I said that the link you'd found was going to be appropriate. sorry!

Basically, you needed to use the multiply composition mode. Here's a demo for you to try on. Clicking the 3rd image picks a new colour.

function byId(id){return document.getElementById(id)}
window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
 byId('canvas2').addEventListener('click', onCanvasClicked, false);
 colorize('green');
}

function onCanvasClicked(evt)
{
 var newColour = getRandomColour();
 colorize(newColour);
}

function getRandomColour()
{
 return '#' + Math.floor(Math.random() * (Math.pow(2,24)-1)).toString(16);
}

function colorize(colourToUse)
{
 var mask = byId('maskImg');
 var colorImg = byId('colorImg');

 var width = colorImg.naturalWidth;
 var height = colorImg.naturalHeight;

 // draw the mask image to a canvas
 var can = byId('canvas1');
 var ctx = can.getContext('2d');
 can.width = width;
 can.height = height;
 ctx.drawImage(mask, 0, 0);
 
 // colorize the non transparent areas
 ctx.globalCompositeOperation = "source-in";
 ctx.fillStyle = colourToUse;
 ctx.fillRect(0, 0, can.width, can.height);
 
 
 // draw the combined output
 var can2 = byId('canvas2');
 var ctx2 = can2.getContext('2d');
 can2.width = width;
 can2.height = height;
 
 ctx2.drawImage(colorImg, 0, 0);
 ctx2.globalCompositeOperation = 'multiply';
 ctx2.drawImage(can,0,0);
}
body {
  background-color: ivory;
  padding: 20px;
}

canvas 
{
  border: 1px solid red;
  width: 275px;
  height: 275px;
}

.dontShow
{
 display: none;
}
 <img style='width:275px; height:275px' id='colorImg' src='http://cache1.artprintimages.com/images/spp/living_61_70.jpg'/><canvas id="canvas1"></canvas><canvas id='canvas2'></canvas>

 <!-- much easier than using image pre-loaders. onDocLoaded wont be fired until the html with images,script and css are available or have failed to load-->
 <img class='dontShow' id='maskImg' src='http://cache1.artprintimages.com/images/spp/living_61_70_mask.png'/>
enhzflep
  • 12,927
  • 2
  • 32
  • 51
  • one last question how do i change the second image if i want to do the same with others ? – Habib Rehman Oct 06 '16 at 17:06
  • Awesome, we're both better off then! Um, the mask url is just the one I left in a comment, and is the one that the example application uses. Neither of the images are altered, they're merely drawn to one of the 2 canvases with different comp modes. – enhzflep Oct 06 '16 at 17:06
  • Oops! Well, you could just set the `.src` of the color and mask images to the URL of your new images. E.g `byId('colorImg').src = *yourUrlHere*;` and `byId('maskImg').src = *yourUrlHere*` - you could also pre-load them as your fiddle does and instead of drawing with the `img` element in the html as the source image, you could use the correct pair from your 2 arrays of pre-loaded ones - 1 array for colours and another array for masks. – enhzflep Oct 06 '16 at 17:09
  • ohh no yea thats what i was saying before sorry for that nvm – Habib Rehman Oct 06 '16 at 17:10
  • the .png image has the transparent object of the image – Habib Rehman Oct 06 '16 at 17:11
  • i get it now, for mask url image has to be transparent with those objects we want to show (using photoshop) and the other url is the real image whose color are getting changed. you have used source-in to overlap images and as pixel of top layer are transparent they don't effect by multiply but gets changed by the color we have in random. – Habib Rehman Oct 06 '16 at 17:15
  • 1
    BINGO! I guess you'd just load the colour image into photoshop, create a new layer and then draw the mask into the new layer using the coloured layer as a guide. Then just save the new layer (only) as a PNG and voila! One freshly created mask. :) – enhzflep Oct 06 '16 at 17:17