Understanding pixel density

I have this basic code that displays a grid of squares inside your browser. There is actually a square inside of each square.

Each inner square color takes the color of a corresponding pixel from a webcam feed. The outer square color was basically what the inner square color was last frame.

I use loadPixels() on the webcam to get the array and loop through each square object. It contains an x,y coordinate to take from the webcam feed.

I attempt to parse pixels correctly but for some reason I end up with only half of my image. I've tried many different values for pixel density but none seem to get everything. I don't even know the pixel density of the web cam feed definitely. 1. How do you determine this? 2. What am I doing wrong?

Here is the retrieval code:

function updateAndDisplaySquares() {
    var d = 4; // not sure if that number is correct...
    var w = capture.width;
    capture.loadPixels();
    for (var i = 0; i < squares.length; i++) {
        var x = squares[i].xCoordToGetFromCam;
        var y = squares[i].yCoordToGetFromCam;
        var c = [capture.pixels[(y*w*d+x)*d],
                 capture.pixels[(y*w*d+x)*d+1],
                 capture.pixels[(y*w*d+x)*d+2],
                 capture.pixels[(y*w*d+x)*d+3]];
        squares[i].update(c);
        squares[i].display();
    }
}

The full code...

EDIT: deleted bugged line

var capture;
var innerSquareSizePercent = 0.50;
var transparancyOfInnerSquare = 0.75;
var camWidth;
var camHeight;
var arrayOfDivisibles;
var currentDivisibleIndex; // which item in the array
var squares; // contains many Square class objects

function setup() {
    createCanvas(windowWidth, windowHeight);
    frameRate(30);
    console.log("window height is: " + windowHeight)

    capture = createCapture(VIDEO);
    capture.size(320, 240); // 320, 240
    capture.hide();
    camWidth = capture.width;
    camHeight = capture.height;

    arrayOfDivisibles = getDivisibleIntegers(camWidth, camHeight);
    currentDivisibleIndex = arrayOfDivisibles.length - 1;

    reconfigure();
}

function draw() {
    background(255);

    updateAndDisplaySquares();

    displayFrameRate();
}

function displayFrameRate() {
    var fr = Math.round(frameRate());
    fill(127, 80);
    textSize(20);
    text(fr, 20, 20);
}

function updateAndDisplaySquares() {
    var d = 4;
    var w = capture.width;
    capture.loadPixels();
    for (var i = 0; i < squares.length; i++) {
        var x = squares[i].xCoordToGetFromCam;
        var y = squares[i].yCoordToGetFromCam;
        var c = [capture.pixels[(y*w*d+x)*d],
                 capture.pixels[(y*w*d+x)*d+1],
                 capture.pixels[(y*w*d+x)*d+2],
                 capture.pixels[(y*w*d+x)*d+3]];
        // basically, we pass in the array, which is a slice of the giant pixels array.
        // This slice contains the desired pixel color in the form of an array.
        squares[i].update(c);
        squares[i].display();
    }
}

// square class
function Square(iSL, iX, iY) {
    this.sideLength = iSL;
    this.x = iX;
    this.y = iY;
    this.innerSideLength = this.sideLength * innerSquareSizePercent;
    this.offset = (this.sideLength - this.innerSideLength) / 2;
    this.innerX = this.offset + this.x;
    this.innerY = this.offset + this.y;
    this.squareCenterX = this.x + (this.sideLength / 2);
    this.squareCenterY = this.y + (this.sideLength / 2);
    this.xCoordToGetFromCam = Math.round((this.x * camWidth) / width);
    this.yCoordToGetFromCam = Math.round((this.y * camHeight) / height);
    this.c = color(255, 255, 255);
    this.previousColor = (255, 255, 255);

    this.update = function(col) {
        this.previousColor = this.c;
        this.c = col;
    }

    this.display = function() {
        noStroke();

        // outer
        fill(this.previousColor);
        rect(this.x, this.y, this.sideLength, this.sideLength);

        // inner
        fill(this.c, transparancyOfInnerSquare);
        rect(this.innerX, this.innerY, this.innerSideLength, this.innerSideLength);
    }
}

// gets divisible integers of the width and height
function getDivisibleIntegers(int1, int2) {
    var arr = [];
    var i;
    if (int1 > int2) {
        for (i = 3; i < int1; i++) {
            if (int1 % i === 0) {
                if (int2 % i === 0) {
                    arr.push(i);
                }
            }
        }
    }

    if (int2 > int1) {
        for (i = 3; i < int2; i++) {
            if (int2 % i === 0) {
                if (int1 % i === 0) {
                    arr.push(i);
                }
            }
        }
    }
    return arr;
}

function reconfigure() {
    squares = []; //# should this be  [] or {}?
    var squareSize = arrayOfDivisibles[currentDivisibleIndex];
    var numXSquares = Math.round(width / squareSize);
    var numYSquares = Math.round(height / squareSize);
    var numberOfSquares = numXSquares * numYSquares;

    console.log("num x squares is: " + numXSquares)
    console.log("num y squares is: " + numYSquares);

    for (var i = 0; i < numXSquares; i++) {
        for (var j = 0; j < numYSquares; j++) {
            var squareTopLeftX = i * squareSize;
            var squareTopLeftY = j * squareSize;
            var square = new Square(squareSize, squareTopLeftX, squareTopLeftY);
            squares.push(square);
        }
    }

    console.log("number of squares is: " + squares.length)
    console.log(squares)

}

Answers

  • edited September 2015

    It's hard to help you when the code already throws exceptions like: capture.pixelDensity(4);
    "Uncaught TypeError: capture.pixelDensity is not a function"
    AFAIK, pixelDensitity isn't a function but a simple numerical property w/ initial value = 1. :-@

    And that's the problem: I don't think pixelDensitity is ever reassigned to anything else.
    And even if we do it manually, I doubt it'd make any diff. at all! /:)

    I believe you know that "Java Mode"'s Video library is a subclass of PImage.
    Unfortunately in p5.js, its corresponding p5.MediaElement doesn't inherit from p5.Image.

    That makes that framework's logic very fragmented and harder to study its source code.
    Having custom method implementations that don't take in consideration every needed aspect.
    In this particular case, property pixelDensitity is apparently ignored by method size()! 8-}

    I've already ranted about it in some previous forum thread of yours: :P
    http://forum.Processing.org/two/discussion/12040/best-way-to-whiten-out-area

  • edited September 2015

    Actually, I apologize. I knew that line didn't work. I thought I took it out before I pasted it in here but I guess not. Removed now.

    Yeah, just checked the sourcecode, you're right, it's just a property, not a method. And the value is 1 on my box. I've been trying to reduce this down to the simplest example I can. Here is a 33 line example of something that I think should work. I added ()'s around pd+1 to be (pd + 1) etc. Seems like that should be more correct?

    var capture;
    var camWidth;
    var pd = 1; // pixel Density
    
    function setup() {
        createCanvas(windowWidth, windowHeight);
        frameRate(1); // keep it sane
    
        capture = createCapture(VIDEO);
        capture.size(320, 240); // 320, 240
        capture.hide();
        camWidth = capture.width;
    }
    
    function draw() {
        background(255);
        drawAllPixels();
    }
    
    function drawAllPixels() {
        var x, y;
        capture.loadPixels();
        for (x = 0; x < 320; x++) {
            for (y = 0; y < 240; y++) {
                stroke([capture.pixels[(y*camWidth*pd+x)*pd],
                        capture.pixels[(y*camWidth*pd+x)*(pd+1)],
                        capture.pixels[(y*camWidth*pd+x)*(pd+2)],
                        capture.pixels[(y*camWidth*pd+x)*(pd+3)]])
                point(x, y);
            }
        }
    }
    

    I'm not knowledgeable enough to understand all of your post but here I tried to distill the problem down to possibly another rabbit hole.

Sign In or Register to comment.