Ask Your Question
0

How can you use K-Means clustering to posterize an image using opencv javascript?

asked 2019-01-07 10:33:25 -0600

Dc gravatar image

updated 2019-01-08 10:34:58 -0600

berak gravatar image

How can you use K-Means clustering to posterize an image using opencv javascript?` Here I attach the code I have

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<script onload="onOpenCvReady();" src="opencv.js" async="" type="text/javascript"></script>
<h1>K Means Example</h1>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput"><img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input id="fileInput" name="file" type="file" /></div>
</div>
<div class="inputoutput"><canvas id="canvasOutput"></canvas>
<div class="caption">canvasOutput</div>
</div>
<script type="text/javascript">let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
  imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
imgElement.onload = function() {
  let mat = cv.imread(imgElement);

let sample= new cv.Mat(mat.rows * mat.cols, 3, cv.CV_32F);
for( var y = 0; y < mat.rows; y++ )
    for( var x = 0; x < mat.cols; x++ )
      for( var z = 0; z < 3; z++)
        sample.ptr(y + x*mat.rows)[z] = mat.ucharPtr(y,x)[z];

  var clusterCount = 4;
  var labels= new cv.Mat();
  var attempts = 5;
  var centers= new cv.Mat();
  var crite= cv.TermCriteria(cv.CV_TERMCRIT_ITER, 10000, 0.0001);
  var criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0);
  cv.kmeans(sample, clusterCount, labels, criteria, attempts, cv.KMEANS_PP_CENTERS, centers );
  mat.delete();
};
function onOpenCvReady() {
  document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}</script>
</div>
</body>
</html>`
edit retag flag offensive close merge delete

Comments

There exist a post How can you use K-Means clustering to posterize an image using c++?, but some functions are different in javascript. I am trying to do something similar but using the web browser only. Thanks in advance

Dc gravatar imageDc ( 2019-01-07 10:40:26 -0600 )edit

show, what you have, so far ;)

berak gravatar imageberak ( 2019-01-07 10:49:05 -0600 )edit

@Dc, you got all my sympathy, but the problem here is: opencv.js is entirely unexplored territory ;(

opencv folks rarely know (modern) js, webdevs have no clue about computer-vision, also the intersection of "known" error msgs between both worlds is exactly null.

i can't answer, either, but the general strategy should be:

  1. make a 1 channel, 3 cols, n (count of all pixels in the image) rows Mat from your image (so each pixel is on it's own row) (maybe use reshape() for this)
  2. apply kmeans. that should give you a list of new color clusters(centers), and labels(cluster indices for each pixel)
  3. replace each pixel color in the original image with the cluster center found from the resp. pixel's labels index
berak gravatar imageberak ( 2019-01-08 10:06:20 -0600 )edit

@Dc, it would be nice, if you could put all of the code into your question, and delete the comments.

i'll promise to help with the formatting ;)

berak gravatar imageberak ( 2019-01-08 10:23:46 -0600 )edit
1

I have created the Mat as you describe in 1. In step 2, the parameters are declared similar like C++ example, I think the error is there.

Dc gravatar imageDc ( 2019-01-08 10:26:53 -0600 )edit
1

@berak, I already put the code as you said

Dc gravatar imageDc ( 2019-01-08 10:34:48 -0600 )edit

@Dc, i removed all of your comments, containing the code resp. to your question, hope, that's ok ;)

berak gravatar imageberak ( 2019-01-08 11:59:17 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2019-01-09 14:47:43 -0600

Dc gravatar image

After some attempts I already solved the errors: 1- sample Mat must be float32 so, sample.floatPtr(y + x*mat.rows)[z] = mat.ucharPtr(y,x)[z]; 2- TermCriteria is an object an it has to be created with new 3- In opencv.js the constants cv.TERM_CRITERIA_EPS and cv.TERM_CRITERIA_MAX_ITER are different cv.TermCriteria_EPS + cv.TermCriteria_MAX_ITER

The code is working, the only thing outputImage is float32 and the original image I used was u8Int, I am figuring out how convert it from float32 to u8int

`

<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<script onload="onOpenCvReady();" src="opencv.js" async="" type="text/javascript"></script>
<h1>K Means Example</h1>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput"><img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input id="fileInput" name="file" type="file" /></div>
</div>
<div class="inputoutput"><canvas id="canvasOutput"></canvas>
<div class="caption">canvasOutput</div>
</div>
<script type="text/javascript">let imgElement = document.getElementById('imageSrc');
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
  imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
imgElement.onload = function() {
  let mat = cv.imread(imgElement);

let sample= new cv.Mat(mat.rows * mat.cols, 3, cv.CV_32F);
for( var y = 0; y < mat.rows; y++ )
    for( var x = 0; x < mat.cols; x++ )
      for( var z = 0; z < 3; z++)
        sample.floatPtr(y + x*mat.rows)[z] = mat.ucharPtr(y,x)[z];

  var clusterCount = 8;
  var labels= new cv.Mat();
  var attempts = 5;
  var centers= new cv.Mat();

  var crite= new cv.TermCriteria(cv.TermCriteria_EPS + cv.TermCriteria_MAX_ITER, 10000, 0.0001);
  var criteria = [1,10,0.0001];

  cv.kmeans(sample, clusterCount, labels, crite, attempts, cv.KMEANS_RANDOM_CENTERS, centers );

 var newImage= new cv.Mat(mat.size(),mat.type());
 for( var y = 0; y < mat.rows; y++ )
    for( var x = 0; x < mat.cols; x++ )
    { 
      var cluster_idx = labels.intAt(y + x*mat.rows,0);
      newImage.floatPtr(y,x)[0] = centers.floatAt(cluster_idx, 0);
      newImage.floatPtr(y,x)[1] = centers.floatAt(cluster_idx, 1);
      newImage.floatPtr(y,x)[2] = centers.floatAt(cluster_idx, 2);
      newImage.floatPtr(y,x)[3] = 255;

    }
  cv.imshow('canvasOutput', newImage);
  mat.delete();

}

function onOpenCvReady() {
  document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}</script>
</div>
</body>
</html>

strong text`:

edit flag offensive delete link more

Comments

1

@berak, Both methods fail to assign correctly the u8Int value (newImage.convertTo(dst,CV_8U) and newImage.ucharPtr(y,x)[0]= centers.floatAt(cluster_idx,0)). The result is taken the first byte of the float32 and assigning it, for instance if value is 136.1971893310547 , the binary representation corresponds to 01000011 00001000 00110010 01111011, the first byte is 01111011 and corresponds to 123, so 123 is the wrong value set as the result and not 136. ( integer has also 4 bytes and the problem will be same ) . As an alternative, the float32 can be transformed using a ceil(centers.floatAt(cluster_idx, 0)) , then, constructing a function with mod it can be transform to binary 8 bits.

Dc gravatar imageDc ( 2019-01-10 09:47:21 -0600 )edit

@Dc, nice analysis ! ;)

and yea, i deleted the comment, after trying my own dogfood there

berak gravatar imageberak ( 2019-01-10 10:02:22 -0600 )edit

Here I attach some code to obtain a newImage as u8Int `

for( var y = 0; y < mat.rows; y++ )
    for( var x = 0; x < mat.cols; x++ )
    { 
      var cluster_idx = labels.intAt(y + x*mat.rows,0);
      var redChan = new Uint8Array(1);
      var greenChan = new Uint8Array(1);
      var blueChan = new Uint8Array(1);
      var alphaChan = new Uint8Array(1);
        redChan[0]=centers.floatAt(cluster_idx, 0);
      greenChan[0]=centers.floatAt(cluster_idx, 1);
       blueChan[0]=centers.floatAt(cluster_idx, 2);
      alphaChan[0]=255;
      newImage.ucharPtr(y,x)[0] =  redChan;
      newImage.ucharPtr(y,x)[1] =  greenChan;
      newImage.ucharPtr(y,x)[2] =  blueChan;
      newImage.ucharPtr(y,x)[3] =  alphaChan;}

`

Dc gravatar imageDc ( 2019-01-11 09:05:01 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2019-01-07 10:33:25 -0600

Seen: 1,392 times

Last updated: Jan 09 '19