Method to remove small regions from binary image : Javascript - javascript

I have an image like this:
(just an binary image of ones and zeros)
... and I'D like to get something like this:
Is there an efficient & fast way to remove small regions from the image (1/0-matrix) using pure javascript?
This is what my matrix (generated from the picture on above) looks like:
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111010001111111111111111111111111111111111111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110001101110
111111111111111111111111111111110011111111111111111111111111111111111111111111111111111111111111111111111111111110000011111111111111111111111111111111111111111111111111111111111111111111110100000000110
111111111111111111111111111000000000111111111111111111111111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111111111111111111111000000000000
111111111111111111111111110000000000001111111111111111111111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111111111111111111111111000000000000
111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111000000000000000111111111111111111111111111111111111111111111111111111111111111111000000000000
111111111111111111111111000000000000000011111111111111111111111111111111110000111111111111111111111111111110000000000000000011111111111111111111111111111110000000011111111111111111111111111000000000000
111111111111111111111110000000000010000011111111111111111111111111111110000000000111111111111111111111111100000000000000000011111111111111111111111111110000000000000111111111111111111111111000000000000
111111111111111111111100000000000000000001111111111111111111111111110000000000000001111111111111111111111100000000001000000001111111111111111111111111100000000000000011111111111111111111111000000000000
111111111111111111111100000010100001000001111111111111111111111111100000000000000000111111111111111111111100000000010001000001111111111111111111111111000001000000000001111111111111111111111100000000000
111111111111111111111100000000100110000001111111111111111111111111100000000000000000111111111111111111111000000000000010000001111111111111111111111111000000000000000000111111111111111111110100000000000
110111111111111111111100000001000000000001111111111111111111111111000000000000000000011111111111111111111000000000011000000001111111111111111111111110000000000000000000011111111111111111111100000000000
110111111111111111111100000000000010001000111111111111111111111111000000000010000000011111111111111111111000000000100000000000111111111111111111111110000000000000000000011111111111111111111100000000000
110111111111111111111000000000100000000000111111111111111111111110000000000000100000001111111111111111111000000100001000000000111111111111111111111110000000000000000000011111111111111111111100000000000
110111111111111111111100001000010011000000111111111111111111111110000000001000000010001111111111111111111000000000000000000000111111111111111111111110000000000000000000001111111111111111111000000010100
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111100000000000000000000101111111111111111111000000000010
110111111111111111111100000000000000000000111111111111111111111110000000000000011000001111111111111111111000000000000000000000111111111111111111111100000000000000000000001111111111111111111100000000010
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111100000000000000000000001110111111111111111100000000000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111110000000000000000000011111111111111111111100000000010
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111100000000000000000000111111111111111111111101000000000000000000001111111111111111111000000001000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111110000000000010000000001111111111111111111100000000000
110111111111111111111100000000000000010000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111100000000000000000000001111111111111111111110000000010
110111111111111111111000000000000000000000011111111111111111111110000000000000000000000111111111111111111000000000000000000000111111111111111111111110000000000000000000001111111111111111111100000000000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000000111111111111111111000000000000000000000111111111111111111111100000000001000000000001111111111111111111100000000000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111000000000000000000000111111111111111111111101000000000000000000011101111111111111111100000000000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111100000000000000000000111111111111111111111101100000000010000000001111111111111111111100000000000
110111111111111111111100000000000000000000111111111111111111111110000000000000000000001111111111111111111100000000000000000000111111111111111111111100000000000000000000001111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000000111111111111111111100000000000000000000111111111111111111111100000000011000000000011111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110100000000000000000000111111111111111111100000000000000000000111111111111111111111100000010000001010000111110111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000111111111111111111111101000000000000000000101111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000111111111111111111111100000000100000000000001111111111111111111110000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000000111111111111111111100000000000000000000011111111111111111111110000010000000000000001111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111100000000000000000000000111111111111111111100000000000000000000011111111111111111111100001000000000000000001111111111111111111100000000010
110111111111111111111100000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111110000100000000000000101111111111111111111110000000010
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000010
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100001000000000000000101111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111110000000000000000000001110111111111111111100000000000
110111111111111111111100000000000000000000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100000000100001010000011111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100000000000000000000001111111111111111111110000001000000000000001111111111111111111100000000000010010000011111111111111111111110000000000000000000011111111111111111111110000000000
110111111111111111111100000000001000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100001000000000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111110000000000000000000011111111111111111111110000000000
110111111111111111111100000000000000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111110000000000
110111111111111111111100000000000000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100000000000000000000001111111111111111111110000000000000000000001111111111111111111000000000000000000010001111111111111111111100000000000000000000011111111111111111111100000000010
110111111111111111111100000000000000000000000111111111111111111110000000000000000000001111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100000000000000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111100001000000000000000001111111111111111111110000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000100
110111111111111111111100000000000000000000001111111111111111111110000000000000000000001111111111111111111100000000000000000000001111111111111111111100000000000000000000011110111111111111111101000000000
110111111111111111111110000000000000000000001111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111110000000000000000000001111111111111111111110000000000000000000011111111111111111111100000000100000000000001111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111110000000000000000000001111111111111111111110000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111110000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000001111111111111111111110000000000000000000011111111111111111111100000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111110000000000000000000011111111111111111111110000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111110000000100000000000000111111111111111111100000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111110000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000000000000011110111111111111111100000000000
110111111111111111111110000000000000000000001111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111110000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000010
110111111111111111111110000000110001011000000111111111111111111110000000001000000000011111111111111111111100000000000000000000001111111111111111111100000000000000000000011111111111111111111100000000000
110111111111111111111110000000000000000000000111111111111111111110000000000000000000011111111111111111111100000000000010000000001111111111111111111100000000000000000000011111111111111111111110000000000
110111111111111111111111000000110001011000000111111111111111111110000001000000000000011111111111111111111100000000000000011010001111111111111111111100000000000000000000011111111111111111111110000000000
111111111111111111111111000000000010100000001111111111111111111110000000000100000000011111111111111111111110000000000000000100011111111111111111111100000000000000000000011111111111111111111110000000000
111111111111111111111111000000000100000000001111111111111111111110000000000110000000011111111111111111111110000000000100000000011111111111111111111100000000000000000000011111111111111111111100000000000
111111111111111111111111000000000000000000001111111111111111111110000000011000010000011111111111111111111110000000000000000000011111111111111111111100000000000000000000011111111111111111111110000000010
111111111111111111111111100000000000001000011111111111111111111110000000000001101100011111111111111111111111000000000000000000111111111111111111111110000000000000000000111111111111111111111110000000000
111111111111111111111111110000000000000000011111111111111111111110000000100001000000111111111111111111111111100000000000000001111111111111111111111110000000000000000000111111111111111111111100000001000
111111111111111111111111110000000000000000111111111111111111111111000000000000000000111111111111111111111111110000000000000001111111111111111111111111000000000000000001111111111111111111111100000000000
111111111111111111111111111100000000000011111111111111111111111111000000000001000000111111111111111111111111111000000000000111111111111111111111111111000000001000001001111111111111111111111110000000000
111111111111111111111111111110000000001111111111111111111111111111100000000000000001111111111111111111111111111110000000011111111111111111111111111111100000000000000011111111111111111111111110000000000
111111111111111111111111111111111111111111111111111111111111111111110000000000000011111111111111111111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111110000000000
111111111111111111111111111111111111111111111111111111111111111111111000000000000111111111111111111111111111111111111111111111111111111111111111111111111000000001001111111111111111111111111110000000000
111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111100011111111111111111111111111111110000000000
111111111111111011111111111111111111111111111111111111111111111111111111000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000010
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000011110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
This question is an edit to the JAVA based question here.
This is another picture symbolizing my idea!

I don't know if it fit your needs but a median filter might be a good starting point.
Note: This example uses node-imagemagick (plus NodeJs) and requires ImageMagick CLI.
Install node-imagemagick from command line with:
npm install imagemagick
Then apply a median -median filter to image.png with radius = 5 and save the filtered image with the following code:
var path = require('path');
var im = require('imagemagick');
var radius = 5;
im.convert([path.join(__dirname +'/image.png'), '-median', radius , path.join(__dirname +'/image'+radius+'.png')],
function(err, stdout){
if (err) throw err;
});
Radius Value
I tried differente values for "radius", a number between 6-8 looks like the most appropriate.
var path = require('path');
var im = require('imagemagick');
var radiuses = [2,4,6,8];
radiuses.forEach((radius) => {
im.convert([path.join(__dirname +'/image.png'), '-median', radius, path.join(__dirname +'/image'+radius+'.png')],
function(err, stdout){
if (err) throw err;
});
});
Result #1: Link
Result #2: Link
Plain JS
const medianFilter = (image, radius) => {
let width = image.width;
let height = image.height;
var input = image.getImageData(0, 0, image.width, image.height).data;
var output = input;
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var index = (x + y * width) * 4; //Get a pixel index in a 1D array
var bufferRed = [];
var bufferGreen = [];
var bufferYellow = [];
var bufferAlpha = [];
for (var cx = 0; cx < radius; cx++) {
for (var cy = 0; cy < radius; cy++) {
if (x + cx < width && y + cy < height) {
var idx = (x + cx + (y + cy) * width) * 4; //Get a pixel index inside a radius*radius square
bufferRed.push(input[idx]);
bufferGreen.push(input[idx + 1]);
bufferYellow.push(input[idx + 2]);
bufferAlpha.push(input[idx + 3]);
}
}
}
output[index] = median(bufferRed.sort());
output[index + 1] = median(bufferGreen.sort());
output[index + 2] = median(bufferYellow.sort());
output[index + 3] = median(bufferAlpha.sort());
}
}
return output;
}
Full Example Without Node
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas id="src" width="1305" height="569"></canvas>
<canvas id="dest" width="1305" height="569"></canvas>
<script type="text/javascript">
var ctx = document.getElementById('src').getContext("2d");
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.width = img.width;
ctx.height = img.height;
var output = medianFilter(ctx, 7);
var ctx2 = document.getElementById('dest').getContext("2d");
var imageData = new ImageData(output, img.width, img.height);
ctx2.putImageData(imageData, 0, 0);
};
img.src = 'image.png';
function median(numbers) {
var median = 0,
numsLen = numbers.length;
numbers.sort();
if (
numsLen % 2 === 0
) {
median = (numbers[numsLen / 2 - 1] + numbers[numsLen / 2]) / 2;
} else {
median = numbers[(numsLen - 1) / 2];
}
return median;
}
const medianFilter = (image, radius) => {
let width = image.width;
let height = image.height;
var input = image.getImageData(0, 0, image.width, image.height).data;
var output = input;
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var index = (x + y * width) * 4;
var bufferRed = [];
var bufferGreen = [];
var bufferYellow = [];
var bufferAlpha = [];
for (var cx = 0; cx < radius; cx++) {
for (var cy = 0; cy < radius; cy++) {
if (x + cx < width && y + cy < height) {
var idx = (x + cx + (y + cy) * width) * 4;
bufferRed.push(input[idx]);
bufferGreen.push(input[idx + 1]);
bufferYellow.push(input[idx + 2]);
bufferAlpha.push(input[idx + 3]);
}
}
}
output[index] = median(bufferRed.sort());
output[index + 1] = median(bufferGreen.sort());
output[index + 2] = median(bufferYellow.sort());
output[index + 3] = median(bufferAlpha.sort());
}
}
return output;
}
</script>
</body>
</html>
Disclaimer: Median Function, What are the mean and median filters?

Related

Maximum call stack size exceeded when filling a square of only 10 by 10 pixels

I know that with the method I want to perform, only small shapes can be filled. But I want to fill a small square but still get a stack overflow error.
Why it happens?
Maybe I have problems with functions color() or setcolor()?
function func() {
var canvas = document.getElementById("image");
var context = canvas.getContext("2d");
canvas.width = 100;
canvas.height = 100;
var width = 10;
var height = 10;
var x = 0;
var y = 0;
var imagedata = context.createImageData(width, height);
var pixelindex = (y * width + x) * 4;
function color(x, y) {
let pixelindex = (y * width + x) * 4;
return imagedata.data[pixelindex] + "," +
+imagedata.data[pixelindex + 1] + "," +
+imagedata.data[pixelindex + 2] + "," +
+imagedata.data[pixelindex + 3];
}
function setcolor(x, y, cn) {
let colors = cn.split(",");
let pixelindex = (y * width + x) * 4;
imagedata.data[pixelindex] = colors[0];
imagedata.data[pixelindex + 1] = colors[1];
imagedata.data[pixelindex + 2] = colors[2];
imagedata.data[pixelindex + 3] = colors[3];
}
function fill4(x, y, cb = "27,94,32,255", cn = "67,160,71,255") {
if (color(x, y) !== cb && color(x, y) !== cn) {
setcolor(x, y, cn);
fill4(x, y - 1, cb, cn);
fill4(x, y + 1, cb, cn);
fill4(x - 1, y, cb, cn);
fill4(x + 1, y, cb, cn);
}
}
fill4(5, 5);
context.putImageData(imagedata, x, y);
}
<body onload="func();">
<canvas id="image"></canvas>
</body>
Based on all the comments under my question, I rewrote the code a bit. Most importantly, I added the conditions that I was told about. Without these conditions, my function ran indefinitely, which is why the error was received. Now, by executing the code, you can see the correct filling of the square with the selected color.
function func() {
var canvas = document.getElementById("image");
var context = canvas.getContext("2d");
canvas.width = 100;
canvas.height = 100;
var width = 100
var x = 0;
var y = 0;
var zX = 50;
var zY = 50;
var cb = [27,94,32,255];
var cn = [67,160,71,255];
context.strokeStyle = "black";
context.lineWidth = 2;
context.strokeRect(x, y, width, width);
if (zX > x && zX < x + width && zY > y && zY < y + width) {
fill4(zY, zY, cb, cn, context);
}
function fill4(zX, zY, cb, cn, content) {
var imagedata = context.createImageData(1, 1);
for (let i = 0; i < 4; i++) {
imagedata.data[i] = cn[i];
}
var color = context.getImageData(zX, zY, 1, 1).data;
if (zX > x && zX < x + width && zY > y && zY < y + width) {
if (color[0] != cn[0] && color[1] != cn[1] && color[2] != cn[2] && color[3] != cn[3]) {
context.putImageData(imagedata, zX, zY);
setTimeout(function() {
fill4(zX, zY-1, cb, cn, context);
fill4(zX, zY+1, cb, cn, context);
fill4(zX-1, zY, cb, cn, context);
fill4(zX+1, zY, cb, cn, context);
}, 20);
}
}
}
}
<body onload="func();">
<canvas id="image"></canvas>
</body>

Canvas image zooming using Nearest Neighbor Algorithm

I'm using nearest neighbor algorithm to zoom the image on canvas. But, when I move the scaling bar higher, the image have white line that create a square array
Original Image
After I move the scale bar
The zoom is work but the problem is only the white lines.
For the source code I will provide in bottom
1.html
<!DOCTYPE HTML>
<html>
<head>
<title>Prototype PC</title>
</head>
<body>
<canvas id='canvas1'></canvas>
<hr>
<button id='read'>READ IMAGE</button>
<hr>
Scale <input type='range' value='1' min='1' max='5' step='0.25' id='scale'>
<br><button id='default2'>Default Scalling</button>
<hr/>
</body>
<style>
body{
background : rgba(255,255,255,1);
}
</style>
<script src='imagine.js'></script>
<script>
var canvas = document.getElementById('canvas1')
var obj = new pc(canvas)
obj.image2canvas("565043_553561101348179_1714194038_a.jpg")
var tes = new Array()
document.getElementById('read').addEventListener('click',function(){
tes = obj.image2read()
})
document.getElementById('scale').addEventListener('change',function(){
var scaleval = this.value
var xpos = 0
var ypos = 0
var xnow = 0
var ynow = 0
var objW = obj.width
var objH = obj.height
tesbackup = new Array()
for(var c=0; c<tes.length; c++){
temp = new Array()
for(var d=0; d<4; d++){
temp.push(255)
}
tesbackup.push(temp)
}
//end of copy
for(var i=0; i<tes.length; i++){
xpos = obj.i2x(i)
ypos = obj.i2y(i)
xnow = Math.round(xpos) * scaleval)
ynow = Math.round(ypos) * scaleval)
if (xnow < objW && ynow < objH) {
for (var j=0; j<scaleval; j++) {
for (var k=0; k<scaleval; k++) {
var idxnow = obj.xy2i(xnow,ynow)
tesbackup[idxnow][0] = tes[i][0]
tesbackup[idxnow][1] = tes[i][1]
tesbackup[idxnow][2] = tes[i][2]
}
}
}
}
obj.array2canvas(tesbackup)
})
</script>
and, for imagine.js
function info(text){
console.info(text)
}
function pc(canvas){
this.canvas = canvas
this.context = this.canvas.getContext('2d')
this.width = 0
this.height = 0
this.imgsrc = ""
this.image2read = function(){
this.originalLakeImageData = this.context.getImageData(0,0, this.width, this.height)
this.resultArr = new Array()
this.tempArr = new Array()
this.tempCount = 0
for(var i=0; i<this.originalLakeImageData.data.length; i++){
this.tempCount++
this.tempArr.push(this.originalLakeImageData.data[i])
if(this.tempCount == 4){
this.resultArr.push(this.tempArr)
this.tempArr = []
this.tempCount = 0
}
}
info('image2read Success ('+this.imgsrc+') : '+this.width+'x'+this.height)
return this.resultArr
}
this.image2canvas = function(imgsrc){
var imageObj = new Image()
var parent = this
imageObj.onload = function() {
parent.canvas.width = imageObj.width
parent.canvas.height = imageObj.height
parent.context.drawImage(imageObj, 0, 0)
parent.width = imageObj.width
parent.height = imageObj.height
info('image2canvas Success ('+imgsrc+')')
}
imageObj.src = imgsrc
this.imgsrc = imgsrc
}
this.array2canvas = function(arr){
this.imageData = this.context.getImageData(0,0, this.width, this.height)
if(this.imageData.data.length != arr.length*4) {
return false
}
for(var i = 0; i < arr.length; i++){
this.imageData.data[(i*4)] = arr[i][0]
this.imageData.data[(i*4)+1] = arr[i][1]
this.imageData.data[(i*4)+2] = arr[i][2]
this.imageData.data[(i*4)+3] = arr[i][3]
}
this.context.clearRect(0, 0, this.width, this.height)
this.context.putImageData(this.imageData, 0, 0)
info('Array2Canvas Success ('+this.imgsrc+')')
}
this.i2x = function(i){
return (i % this.width)
}
this.i2y = function(i){
return ((i - (i % this.width))/ this.width)
}
this.xy2i = function(x,y){
return (y * this.width) + (x)
}
}
Thanks in advance for a solution of this problem
Rounding out pixels
Nearest pixel will result in some zoomed pixels being larger than otheres
It is a problem with the value of scaleval. It has a step of 0.25 and when you calculate each zoomed pixels address you use (and I am guessing as your code has syntax errors) Math.round(xpos * scaleval) but then you draw the pixel using only the fractional size eg 2.75 not the integer size eg 3.0
The size of each pixel is var xSize = Math.round((xpos + 1) * scaleval)-Math.round(xpos * scaleval) same for y. That way when the pixel zoom is not an integer value every so many zoomed pixels will be one pixel wider and higher.
The following is a fix of your code but as you had a number of syntax errors and bugs I have had to guess some of your intentions.
xpos = obj.i2x(i)
ypos = obj.i2y(i)
xnow = Math.round(xpos * scaleval)
ynow = Math.round(ypos * scaleval)
// pixel width and height
var pw = Math.round((xpos + 1) * scaleval) - xnow;
var ph = Math.round((ypos + 1) * scaleval) - ynow;
if (xnow < objW && ynow < objH) {
for (var y = 0; y < ph; y++) {
for (var x =0; x < pw; x++) {
var idxnow = obj.xy2i(xnow + x, ynow + y)
tesbackup[idxnow][0] = tes[i][0]
tesbackup[idxnow][1] = tes[i][1]
tesbackup[idxnow][2] = tes[i][2]
}
}
}
}
But you are not really doing a nearest neighbor algorithm. For that you iterate each of the destination pixels finding the nearest pixel and using its colour. That allows you to easily apply a transform to the zoom but still get every pixel and not skip pixels due to rounding errors.
Nearest neighbor
Example of using nearest neighbor lookup for a scale rotated and translated image
var scaleFac = 2.3; // scale 1> zoom in
var panX = 10; // scaled image pan
var panY = 10;
var ang = 1;
var w = ctx.canvas.width; // source image
var h = ctx.canvas.height;
var wd = ctx1.canvas.width; // destination image
var hd = ctx1.canvas.height;
// use 32bit ints as we are not interested in the channels
var src = ctx.getImageData(0, 0, w, h);
var data = new Uint32Array(src.data.buffer);// source
var dest = ctx1.createImageData(wd, hd);
var zoomData = new Uint32Array(dest.data.buffer);// destination
var xdx = Math.cos(ang) * scaleFac; // xAxis vector x
var xdy = Math.sin(ang) * scaleFac; // xAxis vector y
var ind = 0;
var xx,yy;
for(var y = 0; y < hd; y ++){
for(var x = 0; x < wd; x ++){
// transform point
xx = (x * xdx - y * xdy + panX);
yy = (x * xdy + y * xdx + panY);
// is the lookup pixel in bounds
if(xx >= 0 && xx < w && yy >= 0 && yy < h){
// use the nearest pixel to set the new pixel
zoomData[ind++] = data[(xx | 0) + (yy | 0) * w]; // set the pixel
}else{
zoomData[ind++] = 0; // pixels outside bound are transparent
}
}
}
ctx1.putImageData(dest, 0, 0); // put the pixels onto the destination canvas

createPattern on canvas issue

As on the attached fiddle, the background image on the canvas is just coming and getting disappearing
I tried both createPattern and drawImage both are having same issue.
I am not an expert in Canvas. Any help would be appreciated
(function(){
var canvas = document.getElementById('c'),
/** #type {CanvasRenderingContext2D} */
ctx = canvas.getContext('2d'),
width = 400,
height = 400,
half_width = width >> 1,
half_height = height >> 1,
size = width * (height + 2) * 2,
delay = 30,
oldind = width,
newind = width * (height + 3),
riprad = 3,
ripplemap = [],
last_map = [],
ripple,
texture,
line_width = 20,
step = line_width * 2,
count = height / line_width;
canvas.width = width;
canvas.height = height;
/*
* Water ripple demo can work with any bitmap image
*/
var imageObj = new Image();
imageObj.onload = function() {
var pattern = ctx.createPattern(imageObj, 'repeat');
ctx.rect(0, 0, width, height);
ctx.fillStyle = pattern;
ctx.fill();
ctx.save();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/wood-pattern.png';
with (ctx) {
fillStyle = '#ccc';
fillRect(0, 0, width, height);
fillStyle = '#999999';
save();
rotate(-0.785);
for (var i = 0; i < count; i++) {
fillRect(-width, i * step, width * 3, line_width);
}
}
texture = ctx.getImageData(0, 0, width, height);
ripple = ctx.getImageData(0, 0, width, height);
for (var i = 0; i < size; i++) {
last_map[i] = ripplemap[i] = 0;
}
/**
* Main loop
*/
function run() {
newframe();
ctx.putImageData(ripple, 0, 0);
}
/**
* Disturb water at specified point
*/
function disturb(dx, dy) {
dx <<= 0;
dy <<= 0;
for (var j = dy - riprad; j < dy + riprad; j++) {
for (var k = dx - riprad; k < dx + riprad; k++) {
ripplemap[oldind + (j * width) + k] += 128;
}
}
}
/**
* Generates new ripples
*/
function newframe() {
var a, b, data, cur_pixel, new_pixel, old_data;
var t = oldind; oldind = newind; newind = t;
var i = 0;
// create local copies of variables to decrease
// scope lookup time in Firefox
var _width = width,
_height = height,
_ripplemap = ripplemap,
_last_map = last_map,
_rd = ripple.data,
_td = texture.data,
_half_width = half_width,
_half_height = half_height;
for (var y = 0; y < _height; y++) {
for (var x = 0; x < _width; x++) {
var _newind = newind + i, _mapind = oldind + i;
data = (
_ripplemap[_mapind - _width] +
_ripplemap[_mapind + _width] +
_ripplemap[_mapind - 1] +
_ripplemap[_mapind + 1]) >> 1;
data -= _ripplemap[_newind];
data -= data >> 5;
_ripplemap[_newind] = data;
//where data=0 then still, where data>0 then wave
data = 1024 - data;
old_data = _last_map[i];
_last_map[i] = data;
if (old_data != data) {
//offsets
a = (((x - _half_width) * data / 1024) << 0) + _half_width;
b = (((y - _half_height) * data / 1024) << 0) + _half_height;
//bounds check
if (a >= _width) a = _width - 1;
if (a < 0) a = 0;
if (b >= _height) b = _height - 1;
if (b < 0) b = 0;
new_pixel = (a + (b * _width)) * 4;
cur_pixel = i * 4;
_rd[cur_pixel] = _td[new_pixel];
_rd[cur_pixel + 1] = _td[new_pixel + 1];
_rd[cur_pixel + 2] = _td[new_pixel + 2];
}
++i;
}
}
}
canvas.onmousemove = function(/* Event */ evt) {
disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
};
setInterval(run, delay);
// generate random ripples
var rnd = Math.random;
var timeOut;
var intrvl = setInterval(function() {
clearTimeout(timeOut);
disturb(0, (height/40));
disturb((width/2.67), (height/40));
disturb((width/1.33), (height/40));
disturb(0, (height/2.67));
disturb((width/2.67), (height/2.67));
disturb((width/1.33), (height/2.67));
disturb(0, (height/1.33));
disturb((width/2.67), (height/1.33));
disturb((width/1.33), (height/1.33));
timeOut= setTimeout(function(){
disturb((width/1.8), (height/8));
disturb((width/-1.2), (height/8));
disturb((width/1.14), (height/8));
disturb((width/1.8), (height/2.13));
disturb((width/-1.2), (height/2.13));
disturb((width/1.14), (height/2.13));
disturb((width/1.8), (height/1.03));
disturb((width/-1.2), (height/1.03));
disturb((width/1.14), (height/1.03));;
},300);
}, 700);
setTimeout(function(){
clearInterval(intrvl);
},3000);
})();
this is the link to the fiddle

Javascript Bradley adaptive thresholding implementation

I have been trying to implement Bradley Adaptive thresholding. I know there is a python code in one of the stack overflow questions. But i am struggling to implement the same in JS by following that. Can anyone please help me? So far my code is:
function computeAdaptiveThreshold (imagetest,imageWidth,imageHeight,callback)
{
var size = imageWidth*imageHeight*4;
var s = imageWidth/8;
var s2=s>>1;
var t=0.15;
var it=1.0-t;
var i,j,diff,x1,y1,x2,y2,ind1,ind2,ind3;
var sum=0;
var ind=0;
var integralImg = [];
var canvas = document.createElement('canvas');
var bin = canvas.getContext('2d').createImageData(imageWidth, imageHeight);
for(i=0;i<imageWidth;i++)
{
sum = 0;
for(j=0;j<imageHeight;j++)
{
index = i *imageHeight + j;
sum += imagetest.data[index];
if(i== 0)
{
integralImg[index] = sum;
}
else
{
//index = (i-1) * height + j;
integralImg[index] = integralImg[(i-1) * imageHeight + j] + sum;
}
}
}
x1=0;
for(i=1;i<imageWidth;++i)
{
sum=0;
ind=i;
ind3=ind-s2;
if(i>s)
{
x1=i-s;
}
diff=i-x1;
for(j=0;j<imageHeight;++j)
{
sum+=imagetest.data[ind];// & 0xFF;
integralImg[ind] = integralImg[(ind-1)]+sum;
ind+=imageWidth;
if(i<s2)continue;
if(j<s2)continue;
y1=(j<s ? 0 : j-s);
ind1=y1*imageWidth;
ind2=j*imageWidth;
if (((imagetest.data[ind3])*(diff * (j - y1))) < ((integralImg[(ind2 + i)] - integralImg[(ind1 + i)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
bin.data[ind3] = 0;
} else {
bin.data[ind3] = 255;
}
ind3 += imageWidth;
}
}
y1 = 0;
for( j = 0; j < imageHeight; ++j )
{
i = 0;
y2 =imageHeight- 1;
if( j <imageHeight- s2 )
{
i = imageWidth - s2;
y2 = j + s2;
}
ind = j * imageWidth + i;
if( j > s2 ) y1 = j - s2;
ind1 = y1 * imageWidth;
ind2 = y2 * imageWidth;
diff = y2 - y1;
for( ; i < imageWidth; ++i, ++ind )
{
x1 = ( i < s2 ? 0 : i - s2);
x2 = i + s2;
// check the border
if (x2 >= imageWidth) x2 = imageWidth - 1;
if (((imagetest.data[ind])*((x2 - x1) * diff)) < ((integralImg[(ind2 + x2)] - integralImg[(ind1 + x2)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
bin.data[ind] = 0;
} else {
bin.data[ind] = 255;
}
}
}
callback(bin);`
I am getting very bad images. I should say i cannot call it as a image.
I think your first effort should be to refactor your code : it will be much easier to handle the index.
Then you'll see that you have issues with your indexes : an image -even a gray one- is an RGBA Array, meaning 4 bytes = 32 bits per pixel.
You could handle this by doing a conversion RGBA-> b&W image, then thresholding, then doing b&w -> RGBA back.
...Or handle the RGBA components as you go. Notice that here you only want to output black or white, so you can create an Int32 view on the array, and write at once R,G,B,A for each pixels.
So some code (working here : http://jsfiddle.net/gamealchemist/3zuopz19/8/ ) :
function computeAdaptiveThreshold(sourceImageData, ratio, callback) {
var integral = buildIntegral_Gray(sourceImageData);
var width = sourceImageData.width;
var height = sourceImageData.height;
var s = width >> 4; // in fact it's s/2, but since we never use s...
var sourceData = sourceImageData.data;
var result = createImageData(width, height);
var resultData = result.data;
var resultData32 = new Uint32Array(resultData.buffer);
var x = 0,
y = 0,
lineIndex = 0;
for (y = 0; y < height; y++, lineIndex += width) {
for (x = 0; x < width; x++) {
var value = sourceData[(lineIndex + x) << 2];
var x1 = Math.max(x - s, 0);
var y1 = Math.max(y - s, 0);
var x2 = Math.min(x + s, width - 1);
var y2 = Math.min(y + s, height - 1);
var area = (x2 - x1 + 1) * (y2 - y1 + 1);
var localIntegral = getIntegralAt(integral, width, x1, y1, x2, y2);
if (value * area > localIntegral * ratio) {
resultData32[lineIndex + x] = 0xFFFFFFFF;
} else {
resultData32[lineIndex + x] = 0xFF000000;
}
}
}
return result;
}
function createImageData(width, height) {
var canvas = document.createElement('canvas');
return canvas.getContext('2d').createImageData(width, height);
}
function buildIntegral_Gray(sourceImageData) {
var sourceData = sourceImageData.data;
var width = sourceImageData.width;
var height = sourceImageData.height;
// should it be Int64 Array ??
// Sure for big images
var integral = new Int32Array(width * height)
// ... for loop
var x = 0,
y = 0,
lineIndex = 0,
sum = 0;
for (x = 0; x < width; x++) {
sum += sourceData[x << 2];
integral[x] = sum;
}
for (y = 1, lineIndex = width; y < height; y++, lineIndex += width) {
sum = 0;
for (x = 0; x < width; x++) {
sum += sourceData[(lineIndex + x) << 2];
integral[lineIndex + x] = integral[lineIndex - width + x] + sum;
}
}
return integral;
}
function getIntegralAt(integral, width, x1, y1, x2, y2) {
var result = integral[x2 + y2 * width];
if (y1 > 0) {
result -= integral[x2 + (y1 - 1) * width];
if (x1 > 0) {
result += integral[(x1 - 1) + (y1 - 1) * width];
}
}
if (x1 > 0) {
result -= integral[(x1 - 1) + (y2) * width];
}
return result;
}

Obtaining color pixel of an image in JavaScript canvas

I'm a little stuck trying to get the pixel color of an image. I need to get the RGB value of a pixel, jump three and store it in an array, but my console always returns [0, 0, 0...].
You have any idea how to do this in a better way?
My code looks like this:
function captureImageData( image )
{
var cnv = document.createElement( 'canvas' );
cnv.width = image.width;
cnv.height = image.height;
var ctx = cnv.getContext( '2d' );
ctx.drawImage( image, 0, 0 );
var imageData = ctx.getImageData( 0, 0, 200, 100 );
var data = imageData.data;
var height = imageData.height;
var width = imageData.width;
for ( var y = 0; y < 100; y += 2 )
{
for ( var x = 0; x < 200; x += 2 )
{
red.push(data[( y * imageData.width + x ) * 4 + 0]);
green.push(data[( y * imageData.width + x ) * 4 + 1]);
blue.push(data[( y * imageData.width + x ) * 4 + 2]);
alpha.push(data[( y * imageData.width + x ) * 4 + 3]);
}
}
console.log( red );
}
How are you passing the image to the function? Try the following, it works fine for me.
Live Demo
var red = [],
green = [],
blue = [],
alpha = [];
function captureImageData(image) {
var cnv = document.createElement('canvas');
cnv.width = image.width;
cnv.height = image.height;
var ctx = cnv.getContext('2d');
ctx.drawImage(image, 0, 0);
var imageData = ctx.getImageData(0, 0, 200, 100);
var data = imageData.data;
var height = imageData.height;
var width = imageData.width;
var index = 0;
for (var y = 0; y < 100; y += 2) {
for (var x = 0; x < 200; x += 2) {
index = (y * imageData.width + x) * 4;
red.push(data[index]);
green.push(data[index + 1]);
blue.push(data[index + 2]);
alpha.push(data[index + 3]);
}
}
// log out any pixel here
console.log(red[1]);
}
var image = new Image();
image.crossOrigin = true;
image.src = "http://i.imgur.com/LdmrhlK.jpg";
image.onload = function () {
captureImageData(this);
}

Categories

Resources