-
Notifications
You must be signed in to change notification settings - Fork 5
Comparing libyuv and blurry
Yusuke Hata edited this page Apr 4, 2021
·
3 revisions
In preparation for calling libyuv with cgo, I have created a wrapper as below.
*image.NewRGBA
in go's ARGBBlur func, but I think it would be better to pass []byte
slice as an argument.
/*
#cgo CFLAGS: -I/path/to/libyuv/include
#cgo LDFLAGS: -L/path/to/libyuv/lib -lyuv
#include "planar_functions.h"
*/
import "C"
import (
"fmt"
"image"
"unsafe"
)
//int ARGBBlur(const uint8_t* src_argb,
// int src_stride_argb,
// uint8_t* dst_argb,
// int dst_stride_argb,
// int32_t* dst_cumsum,
// int dst_stride32_cumsum,
// int width,
// int height,
// int radius);
//
func ARGBBlur(src *image.RGBA, width, height int, radius int) (*image.RGBA, error) {
dst := image.NewRGBA(image.Rect(0, 0, width, height))
cumsum := make([]int, width*(height+1)*16)
stride := width * 4
ret := C.ARGBBlur(
(*C.uchar)(&src.Pix[0]),
C.int(stride),
(*C.uchar)(&dst.Pix[0]),
C.int(stride),
(*C.int)(unsafe.Pointer(&cumsum[0])),
C.int(stride),
C.int(width),
C.int(height),
C.int(radius),
)
if ret != 0 {
return nil, fmt.Errorf("failed to call ARGBBlur:%d", ret)
}
return dst, nil
}
This result of calling it with radius
of 5 as below.
out, err := ARGBBlur(img, width, height, 5)
if err != nil {
panic(err.Error())
}
This result of calling it with size
of 11 as below.
out, err := blurry.Boxblur(img, 11)
if err != nil {
panic(err.Error())
}
blurry uses DisablePool because of []byte buffer pool implementation of sync.Pool.
I tried it with code below.
func main() {
N := 100
benchmark_libyuv(N)
benchmark_blurry(N)
}
func benchmark_libyuv(N int) {
d, err := png.Decode(bytes.NewReader(data))
if err != nil {
panic(err.Error())
}
img := convert(d)
width, height := wh(img)
t := time.Now()
for i := 0; i < N; i += 1 {
_, _ = ARGBBlur(img, width, height, 5)
}
fmt.Println("ARGBBlur", time.Since(t))
}
func benchmark_blurry(N int) {
d, err := png.Decode(bytes.NewReader(data))
if err != nil {
panic(err.Error())
}
img := convert(d)
blurry.DisablePool()
t := time.Now()
for i := 0; i < N; i += 1 {
_, _ = blurry.Boxblur(img, 11)
}
fmt.Println("BoxBlur", time.Since(t))
}
ARGBBlur 76.697866ms
BoxBlur 142.577851ms
I have created a wrapper as below.
/*
#cgo CFLAGS: -I/path/to/libyuv/include
#cgo LDFLAGS: -L/path/to/libyuv/lib -lyuv
#include "planar_functions.h"
*/
import "C"
import (
"fmt"
"image"
)
//int ARGBSobel(const uint8_t* src_argb,
// int src_stride_argb,
// uint8_t* dst_argb,
// int dst_stride_argb,
// int width,
// int height);
func ARGBSobel(src *image.RGBA, width, height int) (*image.RGBA, error) {
dst := image.NewRGBA(image.Rect(0, 0, width, height))
stride := width * 4
ret := C.ARGBSobel(
(*C.uchar)(&src.Pix[0]),
C.int(stride),
(*C.uchar)(&dst.Pix[0]),
C.int(stride),
C.int(width),
C.int(height),
)
if ret != 0 {
return nil, fmt.Errorf("failed to call ARGBSobel:%d", ret)
}
return dst, nil
}
out, err := ARGBSobel(img, width, height)
if err != nil {
panic(err.Error())
}
out, err := blurry.Sobel(img)
if err != nil {
panic(err.Error())
}
func main() {
N := 100
benchmark_libyuv(N)
benchmark_blurry(N)
}
func benchmark_libyuv(N int) {
d, err := png.Decode(bytes.NewReader(data))
if err != nil {
panic(err.Error())
}
img := convert(d)
width, height := wh(img)
t := time.Now()
for i := 0; i < N; i += 1 {
_, _ = ARGBSobel(img, width, height)
}
fmt.Println("ARGBSobel", time.Since(t))
}
func benchmark_blurry(N int) {
d, err := png.Decode(bytes.NewReader(data))
if err != nil {
panic(err.Error())
}
img := convert(d)
blurry.DisablePool()
t := time.Now()
for i := 0; i < N; i += 1 {
_, _ = blurry.Sobel(img)
}
fmt.Println("Sobel", time.Since(t))
}
ARGBSobel 8.393158ms
Sobel 21.816918ms