-
Wrote an distortion transform as below (using java bind Any idea to improve performance ? Here are time cost in 1000 interations
Codedef distortion(sourceTextImage: VImage)(using arena: Arena) = {
// add padding
val inputVImg = timeStep("embed") {
sourceTextImage.embed(
10, // Adjust padding as needed
10,
sourceTextImage.getWidth() + 20, // Use source image dimensions
sourceTextImage.getHeight() + 20
)
}
val textLayerMapped = timeStep("text_mapped") {
val w = inputVImg.getWidth()
val h = inputVImg.getHeight()
// Create an identity map (R=x, G=y)
val identityMap = timeStep("identityMap") {
VImage.xyz(arena, w, h)
}
// Generate noise for displacement (adjust sigma for distortion strength)
val noise = timeStep("noiseMap") {
VImage.gaussnoise(
arena,
w,
h,
VipsOption.Int(
"sigma",
2
), // Controls distortion intensity (reduced from 5)
VipsOption.Int("mean", 0)
)
}
// Create a 2-band displacement map (noise for x, 0 for y)
val displacementMap = timeStep("displacementMap") {
val zero = VImage
.black(arena, w, h)
VImage.bandjoin(arena, JList.of(noise, zero))
}
// Add displacement to the identity map
val finalMap = timeStep("addDisplacement") {
identityMap.add(displacementMap)
}
// Apply the map
timeStep("mapim") {
inputVImg.mapim(finalMap)
}
}
val bg = timeStep("randomBg") {
randomBg(textLayerMapped.getWidth(), textLayerMapped.getHeight())
}
// Group text processing steps or time individually if needed
val textLayerFinal = timeStep("text_processing") {
textLayerMapped
.linear(
JList.of(1.0, 1.0, 1.0, 0.5),
JList.of(0.0)
) // Make text semi-transparent
.cast(VipsBandFormat.FORMAT_UCHAR)
}
val out = timeStep("composite2") {
bg.composite2(
textLayerFinal,
VipsBlendMode.BLEND_MODE_OVER
)
}
out
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
Hi @jilen, libvips is demand-driven, so you can't really time individual operations. Your program above is not actually processing any pixels -- it's constructing a large pipeline of operations. When you do the final You can run the final save inside a profiler and see which operations are using the most CPU. That might be useful. |
Beta Was this translation helpful? Give feedback.
-
I made a python version of your code (I hope) for benchmarking: #!/usr/bin/env python3
import sys
import pyvips
def noise_warp(image):
image = image.embed(10, 10, image.width + 20, image.height + 20)
distort = pyvips.Image.xyz(image.width, image.height) + \
pyvips.Image.gaussnoise(image.width, image.height, sigma=2, mean=0) \
.bandjoin(0)
return image.mapim(distort)
bg = pyvips.Image.new_from_file(sys.argv[1], access="sequential")
text = noise_warp(pyvips.Image.text(sys.argv[3], rgba=True, dpi=600))
image = bg.composite2(text * [1, 1, 1, 0.5], "over", x=20, y=20)
image.write_to_file(sys.argv[2]) Run with eg.:
So 200ms to load a 1450 x 2048 pixel JPG, render the distorted text in the top-left corner, and save back again. That's fast compared to something like imagemagick, but slow compared to a GPU shader. It depends on your needs, of course. You could make it go a bit quicker by only generating the distortion map once and reusing it 1000 times (save and reuse an image in python with |
Beta Was this translation helpful? Give feedback.
Ah OK.
libvips parallelism is based on regions, typically 128 x 128 pixels. If the images you are working with are small, you'll get little benefit. libvips is designed for processing large images quickly without using much memory.
For small images I'd suggest skia or opencv instead.