Pixelate image in node js - node.js

What I am doing now is, I am getting all pixels with var getPixels = require("get-pixels"), then I am looping over the array of pixels with this code:
var pixelation = 10;
var imageData = ctx.getImageData(0, 0, img.width, img.height);
var data = imageData.data;
for(var y = 0; y < sourceHeight; y += pixelation) {
for(var x = 0; x < sourceWidth; x += pixelation) {
var red = data[((sourceWidth * y) + x) * 4];
var green = data[((sourceWidth * y) + x) * 4 + 1];
var blue = data[((sourceWidth * y) + x) * 4 + 2];
//Assign
for(var n = 0; n < pixelation; n++) {
for(var m = 0; m < pixelation; m++) {
if(x + m < sourceWidth) {
data[((sourceWidth * (y + n)) + (x + m)) * 4] = red;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 1] = green;
data[((sourceWidth * (y + n)) + (x + m)) * 4 + 2] = blue;
}
}
}
}
}
The problem with this method is that the result image is too sharp.
What I am looking for is something, similar to this one which has been done with ImageMagick -sale
The command which I've used for the second one is
convert -normalize -scale 10% -scale 1000% base.jpg base2.jpg
the problem with this method is that I don't know how to specify the actual pixel size.
So is it possible to get the second result with that for loop. Or is better to use imagemagick -scale but if some one can help with the math, so I can have actual pixel size would be great.

Not sure what maths you are struggling with, but if we start with a 600x600 image like this:
Then, if you want the final image to have just 5 blocky pixels across and 5 blocky pixels down the page, you can scale it down to 5x5 and then scale it back up to its original size:
convert start.png -scale 5x5 -scale 600x600 result.png
Or, if you want to go to 10x10 blocky pixels:
convert start.png -scale 10x10 -scale 600x600 result2.png

The way you've written this, the image is processed into pixels of size nxn where n is specified by your pixelation variable. Increasing pixelation will provide the desired "coarseness".

Related

How to draw the scale meter/ ruler for the 3D model in WebGL

I want to draw a fixed horizontal line (or a ruler) that gives info about size/distance or zooming factor like the one in Google Maps (see here).
Here is the another example with different zoom levels and camera used is orthographic
I try to implement the same with perspective camera but I would not able do it correctly
Below is the result I am getting with perspective camera
The logic that i am using to draw the ruler is
var rect = myCanvas.getBoundingClientRect();
var canvasWidth = rect.right - rect.left;
var canvasHeight = rect.bottom - rect.top;
var Canvas2D_ctx = myCanvas.getContext("2d");
// logic to calculate the rulerwidth
var distance = getDistance(camera.position, model.center);
canvasWidth > canvasHeight && (distance *= canvasWidth / canvasHeight);
var a = 1 / 3 * distance,
l = Math.log(a) / Math.LN10,
l = Math.pow(10, Math.floor(l)),
a = Math.floor(a / l) * l;
var rulerWidth = a / h;
var text = 1E5 <= a ? a.toExponential(3) : 1E3 <= a ? a.toFixed(0) : 100 <= a ? a.toFixed(1) : 10 <= a ? a.toFixed(2) : 1 <= a ? a.toFixed(3) : .01 <= a ? a.toFixed(4) : a.toExponential(3);
Canvas2D_ctx.lineCap = "round";
Canvas2D_ctx.textBaseline = "middle";
Canvas2D_ctx.textAlign = "start";
Canvas2D_ctx.font = "12px Sans-Serif";
Canvas2D_ctx.strokeStyle = 'rgba(255, 0, 0, 1)';
Canvas2D_ctx.lineWidth = 0;
var m = canvasWidth * 0.01;
var n = canvasHeight - 50;
Canvas2D_ctx.beginPath();
Canvas2D_ctx.moveTo(m, n);
n += 12;
Canvas2D_ctx.lineTo(m, n);
m += canvasWidth * rulerWidth;
Canvas2D_ctx.lineTo(m, n);
n -= 12;
Canvas2D_ctx.lineTo(m, n);
Canvas2D_ctx.stroke();
Canvas2D_ctx.fillStyle = 'rgba(255, 0, 0, 1)';
Canvas2D_ctx.fillText(text + " ( m )", (m) /2 , n + 6)
Can any one help me ( logic to calculate the ruler Width) in fixing this issue and to render the scale meter / ruler correctly for both perspective and orthographic camera.

How to draw this circle instead of Bresenham's Circle Algorithm

int main()
{
const auto console = ::GetConsoleWindow();
const auto context = ::GetDC(console);
constexpr auto red = RGB(255, 0, 0);
constexpr auto yellow = RGB(255, 255, 0);
RECT rectClient, rectWindow;
GetClientRect(console, &rectClient);
GetWindowRect(console, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2;
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2;
const int radius = 150;
for (int y = -radius; y <= radius; y++)
for (int x = -radius; x <= radius; x++)
if (x * x + y * y <= radius * radius)
SetPixel(context, posx + x, posy + y, red);
}
It gives me this result img
it looks good but i saw this weird pixels at sides (up, down, right, left)
img
and this is what I want (I added some pixels at the top so it looks better)
enter image description here
Your "what I want" looks anti-aliased. So draw anti-aliased.
If the original condition is not met, but x*x + y*y <= (radius+1)*(radius+1) is met then you need a partially-shaded pixel.
Another way to do anti-aliasing is to test not the center of each pixel but the four corners (x \plusminus 0.5, y \plusminus 0.5). If more than zero but fewer than four corners are inside the circle, you need a partially-shaded pixel.

How to get the average color of a specific area in a webcam feed (Processing/JavaScript)?

I'm using Processing to get a webcam feed from my laptop. In the top left corner, I have drawn a rectangle over the displayed feed. I'm trying to get the average color of the webcam, but only in the region contained by that rectangle.
I keep getting color (0, 0, 0), black, as the result.
Thank you all!
PS sorry if my code seems messy..I'm new at Processing and so I don't know if this might be hard to read or contain bad practices. Thank you.
import processing.video.*;
Capture webcam;
Capture cap;
PImage bg_img;
color bgColor = color(0, 0, 0);
int rMargin = 50;
int rWidth = 100;
color input = color(0, 0, 0);
color background = color(255, 255, 255);
color current;
int bgTolerance = 5;
void setup() {
size(1280,720);
// start the webcam
String[] inputs = Capture.list();
if (inputs.length == 0) {
println("Couldn't detect any webcams connected!");
exit();
}
webcam = new Capture(this, inputs[0]);
webcam.start();
}
void draw() {
if (webcam.available()) {
// read from the webcam
webcam.read();
image(webcam, 0,0);
webcam.loadPixels();
noFill();
strokeWeight(2);
stroke(255,255, 255);
rect(rMargin, rMargin, rWidth, rWidth);
int yCenter = (rWidth/2) + rMargin;
int xCenter = (rWidth/2) + rMargin;
// rectMode(CENTER);
int rectCenterIndex = (width* yCenter) + xCenter;
int r = 0, g = 0, b = 0;
//for whole image:
//for (int i=0; i<bg_img.pixels.length; i++) {
// color c = bg_img.pixels[i];
// r += c>>16&0xFF;
// g += c>>8&0xFF;
// b += c&0xFF;
//}
//r /= bg_img.pixels.length;
//g /= bg_img.pixels.length;
//b /= bg_img.pixels.length;
//CALCULATE AVG COLOR:
int i;
for(int x = 50; x <= 150; x++){
for(int y = 50; y <= 150; y++){
i = (width*y) + x;
color c = webcam.pixels[i];
r += c>>16&0xFF;
g += c>>8&0xFF;
b += c&0xFF;
}
}
r /= webcam.pixels.length;
g /= webcam.pixels.length;
b /= webcam.pixels.length;
println(r + " " + g + " " + b);
}
}
You're so close, but missing out one important aspect: the number of pixels you're sampling.
Notice in the example code that is commented out for a full image you're dividing by the full number of pixels (pixels.length).
However, in your adapted version you want to compute the average colour of only a subsection of the full image which means a smaller number of pixels.
You're only sampling an area that is 100x100 pixels meaning you need to divide by 10000 instead of webcam.pixels.length (1920x1000). That is why you get 0 as it's integer division.
This is what I mean in code:
int totalSampledPixels = rWidth * rWidth;
r /= totalSampledPixels;
g /= totalSampledPixels;
b /= totalSampledPixels;
Full tweaked sketch:
import processing.video.*;
Capture webcam;
Capture cap;
PImage bg_img;
color bgColor = color(0, 0, 0);
int rMargin = 50;
int rWidth = 100;
int rHeight = 100;
color input = color(0, 0, 0);
color background = color(255, 255, 255);
color current;
int bgTolerance = 5;
void setup() {
size(1280,720);
// start the webcam
String[] inputs = Capture.list();
if (inputs.length == 0) {
println("Couldn't detect any webcams connected!");
exit();
}
webcam = new Capture(this, inputs[0]);
webcam.start();
}
void draw() {
if (webcam.available()) {
// read from the webcam
webcam.read();
image(webcam, 0,0);
webcam.loadPixels();
noFill();
strokeWeight(2);
stroke(255,255, 255);
rect(rMargin, rMargin, rWidth, rHeight);
int yCenter = (rWidth/2) + rMargin;
int xCenter = (rWidth/2) + rMargin;
// rectMode(CENTER);
int rectCenterIndex = (width* yCenter) + xCenter;
int r = 0, g = 0, b = 0;
//for whole image:
//for (int i=0; i<bg_img.pixels.length; i++) {
// color c = bg_img.pixels[i];
// r += c>>16&0xFF;
// g += c>>8&0xFF;
// b += c&0xFF;
//}
//r /= bg_img.pixels.length;
//g /= bg_img.pixels.length;
//b /= bg_img.pixels.length;
//CALCULATE AVG COLOR:
int i;
for(int x = 0; x <= width; x++){
for(int y = 0; y <= height; y++){
if (x >= rMargin && x <= rMargin + rWidth && y >= rMargin && y <= rMargin + rHeight){
i = (width*y) + x;
color c = webcam.pixels[i];
r += c>>16&0xFF;
g += c>>8&0xFF;
b += c&0xFF;
}
}
}
//divide by just the area sampled (x >= 50 && x <= 150 && y >= 50 && y <= 150 is a 100x100 px area)
int totalSampledPixels = rWidth * rHeight;
r /= totalSampledPixels;
g /= totalSampledPixels;
b /= totalSampledPixels;
fill(r,g,b);
rect(rMargin + rWidth, rMargin, rWidth, rHeight);
println(r + " " + g + " " + b);
}
}
Bare in mind this is averaging in the RGB colour space which is not the same as perceptual colour space. For example, if you average red and yellow you'd expect orange, but in RGB, a bit of red and green makes yellow.
Hopefully the RGB average is good enough for what you need, otherwise you may need to convert from RGB to CIE XYZ colour space then to Lab colour space to compute the perceptual average (then convert back to XYZ and RGB to display on screen). If that is something you're interested in trying, you can find an older answer demonstrating this in openFrameworks (which you'll notice can be similar to Processing in simple scenarios).

d3.js: How to convert edges from lines to curved paths in a network visualization by drawing a quadratic Bezier curve?

I have a d3 network where points are connected by lines. I want to replace the lines with curved SVG paths. I have forgotten the math to calculate the control point's coordinates. Does anyone know how to do this?
For example, look at the image below:
There exist points A and B. I have them connected at present by a line L. I want to replace L with a curve, C. To do that I need to find a line that is perpendicular to the mid-point of line L, of length M (length set as a percentage of L), to be the control point of spline C. Then I need to define an SVG path to define C.
How do I do this in d3 with SVG? I've done this before in Raphael/SVG a long time ago, but the math escapes me. And I'm not sure how its done in D3.
Just to be clear for others, what we're talking about is a quadratic Bezier curve. That gives you a smooth curve between two points with one control point.
The basic method is:
Find your A-B midpoint, call it J.
Do some trig to find the point at the end of line segment M, call it K
Use the SVG Q or T path commands to draw the quadratic Bezier curve, starting from A, going to B, with the control point K. (note that this won't look exactly like your diagram, but that can be tuned by changing the length of M).
Here's a JavaScript function to return the path you'll need:
function draw_curve(Ax, Ay, Bx, By, M) {
// Find midpoint J
var Jx = Ax + (Bx - Ax) / 2
var Jy = Ay + (By - Ay) / 2
// We need a and b to find theta, and we need to know the sign of each to make sure that the orientation is correct.
var a = Bx - Ax
var asign = (a < 0 ? -1 : 1)
var b = By - Ay
var bsign = (b < 0 ? -1 : 1)
var theta = Math.atan(b / a)
// Find the point that's perpendicular to J on side
var costheta = asign * Math.cos(theta)
var sintheta = asign * Math.sin(theta)
// Find c and d
var c = M * sintheta
var d = M * costheta
// Use c and d to find Kx and Ky
var Kx = Jx - c
var Ky = Jy + d
return "M" + Ax + "," + Ay +
"Q" + Kx + "," + Ky +
" " + Bx + "," + By
}
You can see this in action at this jsfiddle or the snippet (below).
Edit: If a quadratic curve doesn't fit, you can pretty easily adapt the function to do cubic Bezier or arc segments.
var adjacencyList = {
1: [2],
2: [3],
3: [1],
};
var nodes = d3.values(adjacencyList),
links = d3.merge(nodes.map(function(source) {
return source.map(function(target) {
return {
source: source,
target: adjacencyList[target]
};
});
}));
var w = 960,
h = 500;
var M = 50;
var vis = d3.select("#svg-container").append("svg")
.attr("width", w)
.attr("height", h);
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([w, h])
.linkDistance(100)
.charge(-100)
.start();
var link = vis.selectAll(".link")
.data(links)
.enter().append("svg:path")
.attr("class", "link");
console.log(link)
var node = vis.selectAll("circle.node")
.data(nodes)
.enter().append("svg:circle")
.attr("r", 5)
.call(force.drag);
force.on("tick", function() {
link.attr("d", function(d) {
return draw_curve(d.source.x, d.source.y, d.target.x, d.target.y, M);
});
node.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
});
function draw_curve(Ax, Ay, Bx, By, M) {
// side is either 1 or -1 depending on which side you want the curve to be on.
// Find midpoint J
var Jx = Ax + (Bx - Ax) / 2
var Jy = Ay + (By - Ay) / 2
// We need a and b to find theta, and we need to know the sign of each to make sure that the orientation is correct.
var a = Bx - Ax
var asign = (a < 0 ? -1 : 1)
var b = By - Ay
var bsign = (b < 0 ? -1 : 1)
var theta = Math.atan(b / a)
// Find the point that's perpendicular to J on side
var costheta = asign * Math.cos(theta)
var sintheta = asign * Math.sin(theta)
// Find c and d
var c = M * sintheta
var d = M * costheta
// Use c and d to find Kx and Ky
var Kx = Jx - c
var Ky = Jy + d
return "M" + Ax + "," + Ay +
"Q" + Kx + "," + Ky +
" " + Bx + "," + By
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #ccc;
fill: none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<body>
<div id="svg-container">
</div>
</body>

How to calculate width, height and position of bezier curve

I have a bezier curve defined by start point, end point and 2 control points (parameters of this: http://www.w3schools.com/tags/canvas_beziercurveto.asp).
First, I need to calculate width and height of this curve. If I make rectangle around a curve, its width and height is what I need.
Then I need to start point (x,y of left top corner) of this rectangle.
How can I calculate that ? Thanks.
For true bounds, you need to compute the extremities of the curve's component functions, then plug those into the bezier function for the (x,y) coordinates for each extremity. I cover this over at http://pomax.github.io/bezierinfo/#extremities, which also explains how to do most of the steps required to get there in the text leading up to the extremities section. paragraphs 11 and 12/13 then cover bounding boxes (plain, which you're probably interested in, and tight, respectively)
I found approximate solution in some other topic (I don't remember which one) but here is simple JS function to calculate it:
function getCurveBoundary(ax, ay, bx, by, cx, cy, dx, dy) {
var tobx = bx - ax;
var toby = by - ay;
var tocx = cx - bx;
var tocy = cy - by;
var todx = dx - cx;
var tody = dy - cy;
var step = 1 / 40; // precission
var d, px, py, qx, qy, rx, ry, tx, ty, sx, sy, x, y, i, minx, miny, maxx, maxy;
function min(num1, num2) {
if (num1 > num2)
return num2;
if (num1 < num2)
return num1;
return num1;
}
function max(num1, num2) {
if (num1 > num2)
return num1;
if (num1 < num2)
return num2;
return num1;
}
for (var i = 0; i < 41; i++)
{
d = i * step;
px = ax + d * tobx;
py = ay + d * toby;
qx = bx + d * tocx;
qy = by + d * tocy;
rx = cx + d * todx;
ry = cy + d * tody;
toqx = qx - px;
toqy = qy - py;
torx = rx - qx;
tory = ry - qy;
sx = px + d * toqx;
sy = py + d * toqy;
tx = qx + d * torx;
ty = qy + d * tory;
totx = tx - sx;
toty = ty - sy;
x = sx + d * totx;
y = sy + d * toty;
if (i == 0)
{
minx = x;
miny = y;
maxx = x;
maxy = y;
}
else
{
minx = min(minx, x);
miny = min(miny, y);
maxx = max(maxx, x);
maxy = max(maxy, y);
}
}
return {x: Math.round(minx), y: Math.round(miny), width: Math.round(maxx - minx), height: Math.round(maxy - miny)};
}
If you're looking for an approximate solution, it's pretty easy to compute a solution that's always big enough to cover the curve, but might be too big.
Beziers satisfy the 'convex hull property' which means that you can take a bounding box of your control points and that will bound the curve itself.
If you're looking for something more accurate, then the simplest way is to evaluate a bunch of different points on the curve and take the bounding box of those points on the curve. You can vary the number of points you test in order to change the quality/speed tradeoff.
If you're looking for something that directly computes the exact answer then what you need is a root finder to look for extrema of the functions x(t) and y(t).

Resources