Skip to content

Commit

Permalink
examples: add seam carving
Browse files Browse the repository at this point in the history
  • Loading branch information
arrufat committed Dec 6, 2024
1 parent 2087d2c commit e6e198a
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 4 deletions.
1 change: 1 addition & 0 deletions examples/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub fn build(b: *std.Build) void {
_ = buildModule(b, "colorspace", target, optimize);
_ = buildModule(b, "face_alignment", target, optimize);
_ = buildModule(b, "perlin_noise", target, optimize);
_ = buildModule(b, "seam_carving", target, optimize);

const fmt_step = b.step("fmt", "Run zig fmt");
const fmt = b.addFmt(.{
Expand Down
1 change: 1 addition & 0 deletions examples/lib/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ <h2>Examples</h2>
<li><a href="colorspace.html">Colorspace</a></li>
<li><a href="face-alignment.html">Face aligment</a></li>
<li><a href="perlin-noise.html">Perlin noise</a></li>
<li><a href="seam-carving.html">Seam carving</a></li>
</ul>
</main>
<script src="main.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion examples/lib/perlin-noise.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ <h1>Perlin Noise</h1>
<label for="lacunarity-range"><code><span id="lacunarity"></span></code></label>
</div>
</fieldset>
<canvas id="canvas" width="512" height="512"></canvas>
<canvas id="canvas-perlin" width="512" height="512"></canvas>
<script src="perlin-noise.js"></script>
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion examples/lib/perlin-noise.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
wasm_exports = obj.instance.exports;
window.wasm = obj;
console.log("wasm loaded");
const canvas = document.getElementById("canvas");
const canvas = document.getElementById("canvas-perlin");
const ctx = canvas.getContext("2d");
const rows = 512;
const cols = 512;
Expand Down
23 changes: 23 additions & 0 deletions examples/lib/seam-carving.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Seam Carving</title>
<link rel="stylesheet" href="styles.css">
<link rel="icon" href="data:image/png;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////8AAD//AAAf/wAAD/8AAA4xB/4OMQf8DgEAAA8DAAAfAQAAGAAAABgAB/wMCAf8D4cAAB+HAAAfzwAAP/8AAH////////////////////////////////////////////8=">
</head>
<body>
<h1>Seam Carving</h1>
<div id="image-container">
<fieldset class="settings-container">
<legend style="color:black;font-weight:bold;font-family:sans-serif;">Settings</legend>
<div id="buttons-container">
<button id="remove-button">Remove seam</button>
</div>
<p id="size"></p>
</fieldset>
<canvas id="canvas-seam"></canvas>
<script src="seam-carving.js"></script>
</div>
</body>
</html>
128 changes: 128 additions & 0 deletions examples/lib/seam-carving.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
(function () {
let wasmPromise = fetch("seam_carving.wasm");
var wasmExports = null;
const text_decoder = new TextDecoder();
let image = null;

const removeButton = document.getElementById("remove-button");
const canvas = document.getElementById("canvas-seam");
const ctx = canvas.getContext("2d");
canvas.ondragover = function (event) {
event.preventDefault();
};

function displayImageSize() {
let sizeElement = document.getElementById("size");
sizeElement.textContent = "size: " + canvas.width + "×" + canvas.height + " px.";
}

canvas.ondrop = function (event) {
event.preventDefault();
let img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
image = ctx.getImageData(0, 0, canvas.width, canvas.height);
original = new ImageData(image.width, image.height);
original.data.set(image.data);
displayImageSize();
};
img.src = URL.createObjectURL(event.dataTransfer.files[0]);
};

function displayImage(file) {
const reader = new FileReader();
reader.onload = function (e) {
const imageData = e.target.result;
const img = document.createElement("img");
img.src = imageData;
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
image = ctx.getImageData(0, 0, canvas.width, canvas.height);
original = new ImageData(image.width, image.height);
original.data.set(image.data);
displayImageSize();
};
};
reader.readAsDataURL(file);
}

const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.style.display = "none";
fileInput.addEventListener("change", function (e) {
const file = e.target.files[0];
displayImage(file);
});

canvas.addEventListener("click", function () {
fileInput.click();
});

function decodeString(ptr, len) {
if (len === 0) return "";
return text_decoder.decode(new Uint8Array(wasmExports.memory.buffer, ptr, len));
}

WebAssembly.instantiateStreaming(wasmPromise, {
js: {
log: function (ptr, len) {
const msg = decodeString(ptr, len);
console.log(msg);
},
now: function () {
return performance.now();
},
},
}).then(function (obj) {
wasmExports = obj.instance.exports;
window.wasm = obj;
console.log("wasm loaded");

let copy = null;
function seamCarve() {
if (copy) {
ctx.putImageData(copy, 0, 0);
}
const rows = image.height;
const cols = image.width;
const rgbaSize = rows * cols * 4;
const rgbaPtr = wasmExports.alloc(rgbaSize);
const seamSize = rows * 4;
const seamPtr = wasmExports.alloc(seamSize);
const extraSize = rows * cols * 10;
const extraPtr = wasmExports.alloc(extraSize);
var rgba = new Uint8ClampedArray(wasmExports.memory.buffer, rgbaPtr, rgbaSize);
var seam = new Uint32Array(wasmExports.memory.buffer, seamPtr, image.height);
image = ctx.getImageData(0, 0, canvas.width, canvas.height);
rgba.set(image.data);
wasmExports.seam_carve(rgbaPtr, rows, cols, extraPtr, extraSize, seamPtr, rows);
canvas.width = cols - 1;
image = ctx.getImageData(0, 0, canvas.width, canvas.height);
rgba = new Uint8ClampedArray(wasmExports.memory.buffer, rgbaPtr, rgbaSize - 4 * rows);

image.data.set(rgba);
ctx.putImageData(image, 0, 0);
copy = ctx.getImageData(0, 0, canvas.width, canvas.height);
displayImageSize();

for (let i = 1; i < rows; ++i) {
ctx.beginPath();
ctx.moveTo(seam[i - 1], [i - 1]);
ctx.lineTo(seam[i], [i]);
ctx.strokeStyle = "red";
ctx.lineWidth = 1;
ctx.stroke();
}

wasmExports.free(rgbaPtr, rgbaSize);
wasmExports.free(extraPtr, extraSize);
}
removeButton.addEventListener("click", () => {
seamCarve();
});
});
})();
8 changes: 6 additions & 2 deletions examples/lib/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
margin: 10px;
}

#video {
position: absolute;
}

#canvas1 {
border: 1px dashed black;
vertical-align: center;
Expand All @@ -30,8 +34,8 @@

#canvas-seam{
border: 1px solid black;
width: 640px;
height: auto;
width: auto;
height: 640px;
}

#toggle-button {
Expand Down
132 changes: 132 additions & 0 deletions examples/src/seam_carving.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
const std = @import("std");
const assert = std.debug.assert;
const builtin = @import("builtin");

const Image = @import("zignal").Image;
const isColor = @import("zignal").colorspace.isColor;
const Rgb = @import("zignal").Rgb;
const Rgba = @import("zignal").Rgba;

pub const std_options: std.Options = .{
.logFn = if (builtin.cpu.arch.isWasm()) @import("js.zig").logFn else std.log.defaultLog,
.log_level = if (builtin.mode == .Debug) .debug else .info,
};

pub fn computeEnergy(
edges: Image(u8),
energy: *Image(u32),
) void {
assert(edges.rows == energy.rows and edges.cols == energy.cols);
const rows = edges.rows;
const cols = edges.cols;
for (0..cols) |c| energy.data[c] = edges.data[c];
for (1..rows) |r| {
for (0..cols) |c| {
var min: u32 = std.math.maxInt(u32);
var i: isize = -1;
while (i <= 1) : (i += 1) {
var x: isize = @as(isize, @intCast(c)) + i;
if (x == energy.cols) x = @intCast(energy.cols - 1);
const y: isize = @as(isize, @intCast(r)) - 1;
if (energy.at(y, x)) |val| {
min = @min(val.*, min);
}
}
const pos = r * edges.cols + c;
energy.data[pos] = edges.data[pos] + min;
}
}
}

pub fn computeSeam(energy: Image(u32), seam: []usize) void {
assert(energy.rows == seam.len);
const row: usize = energy.rows - 1;
seam[row] = 0;
for (0..energy.cols) |c| {
const pos1 = row * energy.cols + c;
const pos2 = row * energy.cols + seam[row];
if (energy.data[pos1] < energy.data[pos2]) {
seam[row] = c;
}
}

var y: isize = @intCast(energy.rows - 2);
while (y >= 0) : (y -= 1) {
const r: usize = @intCast(y);
seam[r] = seam[r + 1];
var i: isize = -1;
while (i <= 1) : (i += 1) {
var x: isize = @as(isize, @intCast(seam[r + 1])) + i;
if (x == energy.cols) x = @intCast(energy.cols - 1);
if (energy.at(y, x)) |curr| {
if (energy.at(y, @intCast(seam[r]))) |prev| {
if (curr.* < prev.*) {
seam[r] = @intCast(x);
}
}
}
}
}
}

pub fn removeSeam(comptime T: type, image: *Image(T), seam: []const usize) void {
assert(image.rows == seam.len);
const size = image.rows * image.cols;
var pos: usize = 0;
for (0..image.rows) |r| {
for (0..image.cols) |c| {
if (c == seam[r]) continue;
image.data[pos] = image.data[r * image.cols + c];
pos += 1;
}
}

image.cols -= 1;
image.data = image.data[0..(size - image.rows)];
}

pub export fn seam_carve(rgba_ptr: [*]Rgba, rows: usize, cols: usize, extra_ptr: ?[*]u8, extra_len: usize, seam_ptr: [*]usize, seam_size: usize) void {
assert(seam_size == rows);
const size = rows * cols;
var image = Image(Rgba).init(rows, cols, rgba_ptr[0..size]);

const allocator: std.mem.Allocator = blk: {
if (extra_ptr) |ptr| {
@setRuntimeSafety(true);
assert(extra_len > size * 9);
var fba = std.heap.FixedBufferAllocator.init(ptr[0..extra_len]);
break :blk fba.allocator();
} else if (builtin.cpu.arch.isWasm() and builtin.os.tag == .freestanding) {
@panic("ERROR: extra_ptr can't be null when running in WebAssembly.");
} else if (builtin.link_libc) {
break :blk std.heap.c_allocator;
} else {
break :blk std.heap.page_allocator;
}
};

var edges = Image(u8).initAlloc(allocator, rows, cols) catch @panic("OOM");
defer edges.deinit(allocator);
image.sobel(allocator, &edges) catch @panic("OOM");

var energy_map = Image(u32).initAlloc(allocator, image.rows, image.cols) catch @panic("OOM");
defer energy_map.deinit(allocator);
computeEnergy(edges, &energy_map);

const seam = seam_ptr[0..seam_size];
computeSeam(energy_map, seam);

removeSeam(Rgba, &image, seam);
}

pub export fn transpose(rgba_ptr: [*]Rgba, rows: usize, cols: usize) void {
for (0..rows) |r| {
for (0..cols) |c| {
const orig_pos = r * cols + c;
const tran_pos = c * rows + r;
const temp = rgba_ptr[orig_pos];
rgba_ptr[orig_pos] = rgba_ptr[tran_pos];
rgba_ptr[tran_pos] = temp;
}
}
}

0 comments on commit e6e198a

Please sign in to comment.