参考 gocv
下载模型
// downlaod.sh
BASE_URL="http://cs.stanford.edu/people/jcjohns/fast-neural-style/models/"
mkdir -p models/instance_norm
cd models/instance_norm
curl -O "$BASE_URL/instance_norm/candy.t7"
curl -O "$BASE_URL/instance_norm/la_muse.t7"
curl -O "$BASE_URL/instance_norm/mosaic.t7"
curl -O "$BASE_URL/instance_norm/feathers.t7"
curl -O "$BASE_URL/instance_norm/the_scream.t7"
curl -O "$BASE_URL/instance_norm/udnie.t7"
mkdir -p ../eccv16
cd ../eccv16
curl -O "$BASE_URL/eccv16/the_wave.t7"
curl -O "$BASE_URL/eccv16/starry_night.t7"
curl -O "$BASE_URL/eccv16/la_muse.t7"
curl -O "$BASE_URL/eccv16/composition_vii.t7"
cd ../../
共十个模型:
main.go
package main
import (
"fmt"
"image"
"os"
"gocv.io/x/gocv"
)
func main() {
// 判断执行指令时的参数个数,参数 0 为运行的主文件,参数 1 为输入源,参数 2 为模型 ,参数 3 为端点,参数 4 为设备
if len(os.Args) < 3 {
fmt.Println("How to run:\ndnn-style-transfer [videosource] [modelfile] ([backend] [device])")
return
}
// 参数转换
deviceID := os.Args[1]
model := os.Args[2]
backend := gocv.NetBackendDefault
if len(os.Args) > 3 {
backend = gocv.ParseNetBackend(os.Args[3])
}
target := gocv.NetTargetCPU
if len(os.Args) > 4 {
target = gocv.ParseNetTarget(os.Args[4])
}
window := gocv.NewWindow("DNN Style Transfer")
defer window.Close()
// 读取的图片位置
img := gocv.IMRead(deviceID, gocv.IMReadColor)
defer img.Close()
// 打开下载好的 DNN 风格迁移模型
net := gocv.ReadNet(model, "")
if net.Empty() {
fmt.Printf("Error reading network model from : %v\n", model)
return
}
defer net.Close()
net.SetPreferableBackend(gocv.NetBackendType(backend))
net.SetPreferableTarget(gocv.NetTargetType(target))
fmt.Printf("Start reading device: %v\n", deviceID)
// 将 image Mat 转换为 DNN 风格迁移模型可以分析的 640x480 Blob
blob := gocv.BlobFromImage(img, 1.0, image.Pt(640, 480), gocv.NewScalar(103.939, 116.779, 123.68, 0), false, false)
// 把转换成的 Blob 放进转换器
net.SetInput(blob, "")
// 通过网络运行一个向前传递
probMat := net.Forward("")
sz := probMat.Size()
dims := sz[2] * sz[3]
out := gocv.NewMatWithSize(480, 640, gocv.MatTypeCV8UC3)
// 取 blob 并从中获取可显示的 image Mat 图像
for i := 0; i < dims; i++ {
r := probMat.GetFloatAt(0, i)
r += 103.939
g := probMat.GetFloatAt(0, i+dims)
g += 116.779
b := probMat.GetFloatAt(0, i+dims*2)
b += 123.68
out.SetUCharAt(0, i*3, uint8(r))
out.SetUCharAt(0, i*3+1, uint8(g))
out.SetUCharAt(0, i*3+2, uint8(b))
}
// 重置窗口大小,这里适应我的电脑屏幕
window.ResizeWindow(1366, 768)
window.IMShow(out)
// 窗口时间
window.WaitKey(1000 * 3)
probMat.Close()
blob.Close()
out.Close()
}
目录结构
运行效果:
// 运行指令, ** 为实际运行的 DNN 模型
go run ./cmd/main.go ./images/003.jpg ./models/**/**.t7 opencv
原图:
效果图:
composition_vii.t7
la_muse.t7
starry_night.t7
the_wave.t7
candy.t7
feathers.t7
instance_norm/la_muse.t7
mosaic.t7
the_scream.t7
udnie.t7
实时转换
通过流来实现实时转换:
// 源代码
// https://github.com/hybridgroup/gocv/blob/release/cmd/dnn-style-transfer/main.go
// What it does:
//
// This example performs real-time style transfer using a deep neural network.
//
// For more information about the model used by this example, go to:
// https://github.com/jcjohnson/fast-neural-style
//
// Download the model file from:
// http://cs.stanford.edu/people/jcjohns/fast-neural-style/models/eccv16/starry_night.t7
//
// How to run:
//
// go run ./cmd/dnn-style-transfer/main.go 0 ~/Downloads/starry_night.t7 openvino fp16
//
package main
import (
"fmt"
"image"
"os"
"gocv.io/x/gocv"
)
func main() {
// 判断执行指令时的参数个数,参数 0 为运行的主文件,参数 1 为输入源,参数 2 为模型 ,参数 3 为端点,参数 4 为设备
if len(os.Args) < 3 {
fmt.Println("How to run:\ndnn-style-transfer [videosource] [modelfile] ([backend] [device])")
return
}
// 参数转换
deviceID := os.Args[1]
model := os.Args[2]
backend := gocv.NetBackendDefault
if len(os.Args) > 3 {
backend = gocv.ParseNetBackend(os.Args[3])
}
target := gocv.NetTargetCPU
if len(os.Args) > 4 {
target = gocv.ParseNetTarget(os.Args[4])
}
// open capture device
webcam, err := gocv.OpenVideoCapture(deviceID)
if err != nil {
fmt.Printf("Error opening video capture device: %v\n", deviceID)
return
}
defer webcam.Close()
window := gocv.NewWindow("DNN Style Transfer")
defer window.Close()
img := gocv.NewMat()
defer img.Close()
// open DNN style transfer model
net := gocv.ReadNet(model, "")
if net.Empty() {
fmt.Printf("Error reading network model from : %v\n", model)
return
}
defer net.Close()
net.SetPreferableBackend(gocv.NetBackendType(backend))
net.SetPreferableTarget(gocv.NetTargetType(target))
fmt.Printf("Start reading device: %v\n", deviceID)
for {
if ok := webcam.Read(&img); !ok {
fmt.Printf("Device closed: %v\n", deviceID)
return
}
if img.Empty() {
continue
}
// convert image Mat to 640x480 blob that the style transfer can analyze
blob := gocv.BlobFromImage(img, 1.0, image.Pt(640, 480), gocv.NewScalar(103.939, 116.779, 123.68, 0), false, false)
// feed the blob into the detector
net.SetInput(blob, "")
// run a forward pass thru the network
probMat := net.Forward("")
sz := probMat.Size()
dims := sz[2] * sz[3]
out := gocv.NewMatWithSize(480, 640, gocv.MatTypeCV8UC3)
// take blob and obtain displayable Mat image from it
for i := 0; i < dims; i++ {
r := probMat.GetFloatAt(0, i)
r += 103.939
g := probMat.GetFloatAt(0, i+dims)
g += 116.779
b := probMat.GetFloatAt(0, i+dims*2)
b += 123.68
out.SetUCharAt(0, i*3, uint8(r))
out.SetUCharAt(0, i*3+1, uint8(g))
out.SetUCharAt(0, i*3+2, uint8(b))
}
window.IMShow(out)
if window.WaitKey(1) >= 0 {
break
}
probMat.Close()
blob.Close()
out.Close()
}
}
效果: