1

According to the library's readme:

ndarrays can be transposed, flipped, sheared and sliced in constant time per operation.

However I cannot find any examples for doing so. How does one apply a shear to a given ndarray?

Hugues M.
  • 19,846
  • 6
  • 37
  • 65
soundly_typed
  • 39,257
  • 5
  • 28
  • 36
  • 1
    can you pls give more information about you really want to? the 1st answer below look to me a pretty answer... – Idemax Jun 26 '17 at 07:15
  • Question asks about shearing, but I'm not sure what OP meant either. Is it [that kind of shearing](https://stackoverflow.com/q/4998587)? The answer does not provide this (I did not downvote, though). I have no idea how ndarray can help do that in constant time: the internal structure (stride, shape...) only allows affine projections ([*Views are affine projections to 1D storage types.*](https://www.npmjs.com/package/ndarray)), and a sheared view does not look like an affine projection. I must be missing something. Anyway, clarification is welcome. – Hugues M. Jun 27 '17 at 09:05
  • Thanks for asking. The shear I'm referring to is a [shear mapping](https://en.wikipedia.org/wiki/Shear_mapping), which seems to be an application of a [shear matrix](https://en.wikipedia.org/wiki/Shear_matrix). – soundly_typed Jun 27 '17 at 16:17
  • Still not sure what you want, but I have something cool... I made [this playground](http://requirebin.com/?gist=abda68898581112db6969ae808050f71) that allows to play with the API on an image. There is an attempt at "constant-time shearing" in there, by playing with the stride. So if someone can figure it out and let us know what to type in there, that might help provide a good answer. (Btw I still don't see how to *shear* with `hi` and `lo` as the only answer suggests). – Hugues M. Jun 27 '17 at 23:25

2 Answers2

2

As clarified in comments, the desired shearing is a sheared mapping.

I found that the easiest to shear an ndarray is to use ndarray-warp.
See here page 5 for details about how shearing is a particular case of warping.

(most interesting things you can do with ndarrays are implemented in the scijs ecosystem of libraries, which revolve around ndarray)

var ndarray = require("ndarray")
var lena = require("lena")
var warp = require("ndarray-warp")
var zeros = require("zeros")
var luminance = require("luminance")
var input = luminance(lena)                    // Input is famous Lena image
var output = require("zeros")([width, height]) // Allocate buffer for output
var shearFunction = function(out, inp) {       // Custom shear function
    out[0] = inp[0]
    out[1] = inp[1] + inp[0]*0.2
}
warp(result, input, shearFunction)

For a complete example, below I transformed Lena 3 times with ndwarp, the bottom 2 are sheared.

Sheared Lena

See it live here (you can even change the code and play with it).

var ndarray = require("ndarray")
var ops = require("ndarray-ops")
var lena = require("lena")
var pool = require("typedarray-pool")
var warp = require("ndarray-warp")
var zeros = require("zeros")
var luminance = require("luminance")
var totalWidth = lena.shape[1]
var totalHeight = lena.shape[0]
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = totalWidth
canvas.height = totalHeight
// lena is 512x512 RGB image, let's get a 256x256 monochrome image
var input = luminance(lena.step(2,2))
var width = totalWidth/2
var height = totalHeight/2
var context = canvas.getContext("2d")
context.fillStyle = "#000"
context.fillRect(0, 0, totalWidth, totalHeight)
drawImage(context, input, 0, 0)

var result = require("zeros")([width, height])

var warpFunction = function(out, inp) {
    var dx = inp[0] - 128
    var dy = inp[1] - 128
    var r  = Math.sqrt(dx * dx + dy * dy)
    var theta = Math.atan2(dy, dx)    
    out[0] = 0.9 * r * Math.cos(theta + 0.01 * r) + 128
    out[1] = 0.7 * r * Math.sin(theta + 0.01 * r) + 128
}
warp(result, input, warpFunction)
drawImage(context, result, 256, 0)

var shearFunction1 = function(out, inp) {
    out[0] = inp[0]
    out[1] = inp[1] + inp[0]*0.2
}
warp(result, input, shearFunction1)
drawImage(context, result, 0, 256)

var shearFunction2 = function(out, inp) {
    out[0] = inp[0] - inp[1]*0.25
    out[1] = inp[1]
}
warp(result, input, shearFunction2)
drawImage(context, result, 256, 256)


function drawImage(context, array, x, y) {
    var pixels = context.getImageData(x, y, width, height)
    var pixelArray = ndarray(pixels.data, [array.shape[0], array.shape[1], 3], [4*width, 4, 1], 0)
    if(array.dimension === 3) {
        ops.assign(
            pixelArray.hi(array.shape[0], array.shape[1], array.shape[2]), array)
    } else {
        ops.assign(pixelArray.pick(-1,-1,0), array)
        ops.assign(pixelArray.pick(-1,-1,1), array)
        ops.assign(pixelArray.pick(-1,-1,2), array)
    } 
    context.putImageData(pixels, x, y)
}

Enjoy.

Hugues M.
  • 19,846
  • 6
  • 37
  • 65
-1

Hope this can help you:

( To "shear" a ndarray, you can use those methods: 'hi' and 'lo' )

var ndarray = require('ndarray');
var mat     = ndarray(new Float64Array([1, 2, 3, 4, 5, 6, 7, 8, 9]), [3, 3]);
console.log(mat);

// 1 2 3
// 4 5 6
// 7 8 9

console.log(mat.get(1, 1)); // 5
console.log(mat.get(5, 0)); // 7
console.log(mat.get(34, 43)); // undefined

mat.set(1, 1, 100);

console.log(mat);

// 1 2   3
// 4 100 6
// 7 8   9

console.log(mat.index(1, 1)); // 4

console.log(mat.size); // 9

console.log(mat.dimension); // 2

var matLo = mat.lo(1, 1);

console.log(matLo);

// 100 6
// 8   9

console.log(matLo.get(0, 0)); // 100
console.log(matLo.get(0, 1)); // 6
console.log(matLo.get(1, 0)); // 8
console.log(matLo.get(1, 1)); // 9

var matHi = mat.hi(1, 1);

console.log(matHi);

// 1 2
// 4 100

console.log(matHi.get(0, 0)); // 1
console.log(matHi.get(0, 1)); // 2
console.log(matHi.get(1, 0)); // 4
console.log(matHi.get(1, 1)); // 100

var matStap = mat.step(-1);

console.log(matStap);

// 7 8   9
// 4 100 6
// 1 2   3

console.log(matStap.get(0, 0)); // 7
console.log(matStap.get(0, 1)); // 8
console.log(matStap.get(0, 2)); // 9
console.log(matStap.get(1, 0)); // 4
console.log(matStap.get(1, 1)); // 100
console.log(matStap.get(1, 2)); // 6
console.log(matStap.get(2, 0)); // 1
console.log(matStap.get(2, 1)); // 2
console.log(matStap.get(2, 2)); // 3

var matTranspose = mat.transpose(1,0);

console.log(matTranspose);

// 1 4   7
// 2 100 8
// 3 6   9

console.log(matTranspose.get(0, 0)); // 1
console.log(matTranspose.get(0, 1)); // 4
console.log(matTranspose.get(0, 2)); // 7
console.log(matTranspose.get(1, 0)); // 2
console.log(matTranspose.get(1, 1)); // 100
console.log(matTranspose.get(1, 2)); // 8
console.log(matTranspose.get(2, 0)); // 3
console.log(matTranspose.get(2, 1)); // 6
console.log(matTranspose.get(2, 2)); // 9
sidanmor
  • 5,079
  • 3
  • 23
  • 31