Created
October 5, 2020 10:02
-
-
Save stengoes/ba2b22ef4954273ae173a3c600811722 to your computer and use it in GitHub Desktop.
image_pad_or_crop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function image_pad_or_crop(image, output_height, output_width) { | |
// Pads or crops an image so that the height and width dimensions match output_height and output_width. | |
// This function is compatible with tf.image.resize_with_crop_or_pad(image, target_height, target_width) | |
// Validate inputs | |
const image_size = image.height * image.width * image.depth; | |
if (image.data.length != image_size) { | |
console.log("Error: image dimensions do not match rgba buffer size!"); | |
return null; | |
} | |
if (image.data.constructor !== Uint8ClampedArray && image.data.constructor !== Float32Array) { | |
console.log("Error: image data should be of type Uint8ClampedArray or Float32Array!"); | |
return null; | |
} | |
if (output_height <= 0 || output_width <= 0) | |
{ | |
console.log("Error: output_height and output_width should be positive integers ( > 0)!"); | |
return null; | |
} | |
// Compute output dimensions | |
const output_depth = image.depth; | |
// Init output image | |
const output = { | |
height: output_height, | |
width: output_width, | |
depth: output_depth, | |
data: new image.data.constructor(output_height * output_width * output_depth) // Initialized with zeros | |
} | |
// Compute padding/cropping amounts | |
function floor(v) { return (v >= 0 || -1) * Math.floor(Math.abs(v));} // use custom floor that is compatible with tf.image.resize_with_crop_or_pad | |
const top = floor((output_height - image.height) / 2); | |
const bottom = output_height - image.height - top; | |
const left = floor((output_width - image.width) / 2); | |
const right = output_width - image.width - left; | |
// Copy input image into output | |
let output_idx = Math.max(top, 0) * output.width * output.depth + Math.max(left, 0) * output_depth; | |
let image_idx = Math.max(-top, 0) * image.width * image.depth + Math.max(-left, 0) * image.depth; | |
for (let y = 0; y < (output_height - Math.max(top, 0) - Math.max(bottom, 0)); y++, image_idx += image.width * image.depth, output_idx += output_width * output.depth) | |
output.data.set(image.data.slice(image_idx, image_idx + (image.width - Math.max(-left, 0) - Math.max(-right, 0)) * image.depth), output_idx) | |
return output; | |
} | |
// Utility function (only for testing) | |
function show_image(image) { | |
str = ""; | |
let idx = 0; | |
for (let y = 0; y < image.height; y++) { | |
for (let x = 0; x < image.width; x++) { | |
str += "[ "; | |
for (let z = 0; z < image.depth; z++) | |
str += image.data[idx++] + " "; | |
str += "] "; | |
} | |
str += "\n"; | |
} | |
console.log(str); | |
} | |
// Test | |
test_image = { | |
"height": 3, | |
"width": 4, | |
"depth": 1, | |
"data": (new Float32Array([...Array(3*4*1).keys()])) | |
} | |
show_image(test_image); | |
/* should output: | |
[ 0 ] [ 1 ] [ 2 ] [ 3 ] | |
[ 4 ] [ 5 ] [ 6 ] [ 7 ] | |
[ 8 ] [ 9 ] [ 10 ] [ 11 ] | |
*/ | |
output = image_pad_or_crop(test_image, 6, 6); | |
show_image(output); | |
/* should output: | |
[ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] | |
[ 0 ] [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 0 ] | |
[ 0 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 0 ] | |
[ 0 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 0 ] | |
[ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] | |
[ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment