Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dnn: allow ReadNet() function to only accept model file, remove Caffe tests, correct ONNX tests #1216

Merged
merged 4 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ jobs:
run: "test -z $(gofmt -l .) || gofmt -d ."
- name: Install dependencies
run: apt-get update -yqq && apt-get install xvfb unzip -y
- name: Install Caffe test model
- name: Install WeChat test model
run: |
mkdir -p ${GITHUB_WORKSPACE}/testdata
curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/bvlc_googlenet.prototxt > ${GITHUB_WORKSPACE}/testdata/bvlc_googlenet.prototxt
curl -sL http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel > ${GITHUB_WORKSPACE}/testdata/bvlc_googlenet.caffemodel
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.caffemodel > ${GITHUB_WORKSPACE}/testdata/detect.caffemodel
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.prototxt > ${GITHUB_WORKSPACE}/testdata/detect.prototxt
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.caffemodel > ${GITHUB_WORKSPACE}/testdata/sr.caffemodel
Expand All @@ -35,14 +33,13 @@ jobs:
- name: Install ONNX test model
run: |
mkdir -p ${GITHUB_WORKSPACE}/testdata
curl -sL https://github.com/onnx/models/blob/master/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx\?raw\=true > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx
curl -sL https://github.com/onnx/models/raw/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx
- name: Run main tests
run: xvfb-run -a --error-file /var/log/xvfb_error.log --server-args="-screen 0 1024x768x24 +extension RANDR" go test -v -coverprofile=/tmp/coverage.out -count=1 -tags matprofile .
env:
DISPLAY: 99.0
GOCV_CAFFE_TEST_FILES: ${{ github.workspace }}/testdata
GOCV_TENSORFLOW_TEST_FILES: ${{ github.workspace }}/testdata
NO_GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata
GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata
- name: Run contrib tests
run: xvfb-run -a --error-file /var/log/xvfb_error.log --server-args="-screen 0 1024x768x24 +extension RANDR" go test -v -coverprofile=/tmp/contrib.out -count=1 -tags matprofile ./contrib
env:
Expand Down
9 changes: 3 additions & 6 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ jobs:
cache: true
- name: Checkout
uses: actions/checkout@v4
- name: Install Caffe test model
- name: Install WeChat test model
run: |
mkdir -p ${GITHUB_WORKSPACE}/testdata
curl -sL https://raw.githubusercontent.com/opencv/opencv_extra/master/testdata/dnn/bvlc_googlenet.prototxt > ${GITHUB_WORKSPACE}/testdata/bvlc_googlenet.prototxt
curl -sL http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel > ${GITHUB_WORKSPACE}/testdata/bvlc_googlenet.caffemodel
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.caffemodel > ${GITHUB_WORKSPACE}/testdata/detect.caffemodel
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/detect.prototxt > ${GITHUB_WORKSPACE}/testdata/detect.prototxt
curl -sL https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/wechat_qrcode/sr.caffemodel > ${GITHUB_WORKSPACE}/testdata/sr.caffemodel
Expand All @@ -44,12 +42,11 @@ jobs:
- name: Install ONNX test model
run: |
mkdir -p ${GITHUB_WORKSPACE}/testdata
curl -sL https://github.com/onnx/models/blob/master/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx\?raw\=true > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx
curl -sL https://github.com/onnx/models/raw/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ${GITHUB_WORKSPACE}/testdata/googlenet-9.onnx
- name: Run main tests
run: go test -v -tags matprofile .
env:
GOCV_CAFFE_TEST_FILES: ${{ github.workspace }}/testdata
GOCV_TENSORFLOW_TEST_FILES: ${{ github.workspace }}/testdata
NO_GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata
GOCV_ONNX_TEST_FILES: ${{ github.workspace }}/testdata
- name: Run contrib tests
run: go test -v -tags matprofile ./contrib
14 changes: 13 additions & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,21 @@ jobs:
echo "CGO_CPPFLAGS=-I${env:GITHUB_WORKSPACE}\opencv\build\install\include" >> $env:GITHUB_ENV
echo "CGO_LDFLAGS=-L${env:GITHUB_WORKSPACE}\opencv\build\install\x64\mingw\lib -lopencv_core4100 -lopencv_face4100 -lopencv_videoio4100 -lopencv_imgproc4100 -lopencv_highgui4100 -lopencv_imgcodecs4100 -lopencv_objdetect4100 -lopencv_features2d4100 -lopencv_video4100 -lopencv_dnn4100 -lopencv_xfeatures2d4100 -lopencv_plot4100 -lopencv_tracking4100 -lopencv_img_hash4100 -lopencv_calib3d4100 -lopencv_bgsegm4100 -lopencv_photo4100 -lopencv_aruco4100 -lopencv_wechat_qrcode4100 -lopencv_ximgproc4100 -lopencv_xphoto4100" >> $env:GITHUB_ENV
echo "${env:GITHUB_WORKSPACE}/opencv/build/install/x64/mingw/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Test GoCV
- name: Install Tensorflow test model
run: |
mkdir -p ./testdata
curl -sL https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip > ./testdata/inception5h.zip
unzip -o ./testdata/inception5h.zip tensorflow_inception_graph.pb -d ./testdata
- name: Install ONNX test model
run: |
curl -sL https://github.com/onnx/models/raw/main/validated/vision/classification/inception_and_googlenet/googlenet/model/googlenet-9.onnx > ./testdata/googlenet-9.onnx
- name: Set GoCV model env
run: |
go env
echo "GOCV_TENSORFLOW_TEST_FILES=${env:GITHUB_WORKSPACE}\testdata" >> $env:GITHUB_ENV
echo "GOCV_ONNX_TEST_FILES=${env:GITHUB_WORKSPACE}\testdata" >> $env:GITHUB_ENV
- name: Test GoCV
run: |
go test -v -tags="matprofile,customenv" .
- name: Test GoCV Contrib
run: |
Expand Down
14 changes: 10 additions & 4 deletions dnn.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,17 @@ func ReadNetBytes(framework string, model []byte, config []byte) (Net, error) {
if err != nil {
return Net{}, err
}
bConfig, err := toByteArray(config)
if err != nil {
return Net{}, err

var bConfig C.ByteArray
if len(config) > 0 {
pbConfig, err := toByteArray(config)
if err != nil {
return Net{}, err
}
bConfig = *pbConfig
}
return Net{p: unsafe.Pointer(C.Net_ReadNetBytes(cFramework, *bModel, *bConfig))}, nil

return Net{p: unsafe.Pointer(C.Net_ReadNetBytes(cFramework, *bModel, bConfig))}, nil
}

// ReadNetFromCaffe reads a network model stored in Caffe framework's format.
Expand Down
210 changes: 33 additions & 177 deletions dnn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,238 +2,94 @@ package gocv

import (
"image"
"io/ioutil"
"os"
"path/filepath"
"testing"
)

func checkNet(t *testing.T, net Net) {
net.SetPreferableBackend(NetBackendDefault)
net.SetPreferableTarget(NetTargetCPU)

img := IMRead("images/space_shuttle.jpg", IMReadColor)
if img.Empty() {
t.Error("Invalid Mat in ReadNet test")
}
defer img.Close()

blob := BlobFromImage(img, 1.0, image.Pt(224, 224), NewScalar(0, 0, 0, 0), false, false)
if blob.Empty() {
t.Error("Invalid blob in ReadNet test")
}
defer blob.Close()

net.SetInput(blob, "data")

layer := net.GetLayer(0)
defer layer.Close()

if layer.InputNameToIndex("notthere") != -1 {
t.Error("Invalid layer in ReadNet test")
}
if layer.OutputNameToIndex("notthere") != -1 {
t.Error("Invalid layer in ReadNet test")
}
if layer.GetName() != "_input" {
t.Errorf("Invalid layer name in ReadNet test: %s\n", layer.GetName())
}
if layer.GetType() != "" {
t.Errorf("Invalid layer type in ReadNet test: %s\n", layer.GetType())
}

ids := net.GetUnconnectedOutLayers()
if len(ids) != 1 {
t.Errorf("Invalid len output layers in ReadNet test: %d\n", len(ids))
}

if len(ids) == 1 && ids[0] != 142 {
t.Errorf("Invalid unconnected output layers in ReadNet test: %d\n", ids[0])
}

lnames := net.GetLayerNames()
if len(lnames) != 142 {
t.Errorf("Invalid len layer names in ReadNet test: %d\n", len(lnames))
}

if len(lnames) == 142 && lnames[1] != "conv1/relu_7x7" {
t.Errorf("Invalid layer name in ReadNet test: %s\n", lnames[1])
}

prob := net.ForwardLayers([]string{"prob"})
if len(prob) == 0 {
t.Error("Invalid len prob in ReadNet test")
}

if prob[0].Empty() {
t.Error("Invalid prob[0] in ReadNet test")
}

probMat := prob[0].Reshape(1, 1)
defer probMat.Close()
_, maxVal, minLoc, maxLoc := MinMaxLoc(probMat)

if round(float64(maxVal), 0.00005) != 0.9998 {
t.Errorf("ReadNet maxVal incorrect: %v\n", round(float64(maxVal), 0.00005))
}

if minLoc.X != 955 || minLoc.Y != 0 {
t.Errorf("ReadNet minLoc incorrect: %v\n", minLoc)
}

if maxLoc.X != 812 || maxLoc.Y != 0 {
t.Errorf("ReadNet maxLoc incorrect: %v\n", maxLoc)
}

perf := net.GetPerfProfile()
if perf == 0 {
t.Error("ReadNet GetPerfProfile error")
}
for _, bl := range prob {
bl.Close()
}
}

func TestReadNetDisk(t *testing.T) {
path := os.Getenv("GOCV_CAFFE_TEST_FILES")
func TestReadNetDiskFromTensorflow(t *testing.T) {
path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES")
if path == "" {
t.Skip("Unable to locate Caffe model files for tests")
t.Skip("Unable to locate Tensorflow model files for tests")
}

net := ReadNet(path+"/bvlc_googlenet.caffemodel", path+"/bvlc_googlenet.prototxt")
net := ReadNet(path+"/tensorflow_inception_graph.pb", "")
if net.Empty() {
t.Errorf("Unable to load Caffe model using ReadNet")
t.Errorf("Unable to load Tensorflow model using ReadNet")
}
defer net.Close()

checkNet(t, net)
checkTensorflowNet(t, net)
}

func TestReadNetMemory(t *testing.T) {
path := os.Getenv("GOCV_CAFFE_TEST_FILES")
func TestReadNetMemoryFromTensorflow(t *testing.T) {
path := os.Getenv("GOCV_TENSORFLOW_TEST_FILES")
if path == "" {
t.Skip("Unable to locate Caffe model files for tests")
t.Skip("Unable to locate Tensorflow model files for tests")
}

bModel, err := ioutil.ReadFile(path + "/bvlc_googlenet.caffemodel")
bModel, err := os.ReadFile(path + "/tensorflow_inception_graph.pb")
if err != nil {
t.Errorf("Failed to load model from file: %v", err)
}

_, err = ReadNetBytes("caffe", nil, nil)
_, err = ReadNetBytes("tensorflow", nil, nil)
if err == nil {
t.Errorf("Should have error for reading nil model bytes")
}

bConfig, err := ioutil.ReadFile(path + "/bvlc_googlenet.prototxt")
if err != nil {
t.Errorf("Failed to load config from file: %v", err)
}

_, err = ReadNetBytes("caffe", bModel, nil)
if err == nil {
t.Errorf("Should have error for reading nil config bytes")
}

net, err := ReadNetBytes("caffe", bModel, bConfig)
net, err := ReadNetBytes("tensorflow", bModel, nil)
if err != nil {
t.Errorf("Failed to read net bytes: %v", err)
}
if net.Empty() {
t.Errorf("Unable to load Caffe model using ReadNetBytes")
t.Errorf("Unable to load Tensorflow model using ReadNetBytes")
}
defer net.Close()

checkNet(t, net)
}

func checkCaffeNet(t *testing.T, net Net) {
img := IMRead("images/space_shuttle.jpg", IMReadColor)
if img.Empty() {
t.Error("Invalid Mat in Caffe test")
}
defer img.Close()

blob := BlobFromImage(img, 1.0, image.Pt(224, 224), NewScalar(0, 0, 0, 0), false, false)
if blob.Empty() {
t.Error("Invalid blob in Caffe test")
}
defer blob.Close()

net.SetInput(blob, "data")
prob := net.Forward("prob")
defer prob.Close()
if prob.Empty() {
t.Error("Invalid prob in Caffe test")
}

probMat := prob.Reshape(1, 1)
defer probMat.Close()
_, maxVal, minLoc, maxLoc := MinMaxLoc(probMat)

if round(float64(maxVal), 0.00005) != 0.9998 {
t.Errorf("Caffe maxVal incorrect: %v\n", round(float64(maxVal), 0.00005))
}

if minLoc.X != 955 || minLoc.Y != 0 {
t.Errorf("Caffe minLoc incorrect: %v\n", minLoc)
}

if maxLoc.X != 812 || maxLoc.Y != 0 {
t.Errorf("Caffe maxLoc incorrect: %v\n", maxLoc)
}
checkTensorflowNet(t, net)
}

func TestCaffeDisk(t *testing.T) {
path := os.Getenv("GOCV_CAFFE_TEST_FILES")
func TestReadNetDiskFromONNX(t *testing.T) {
path := os.Getenv("GOCV_ONNX_TEST_FILES")
if path == "" {
t.Skip("Unable to locate Caffe model files for tests")
t.Skip("Unable to locate ONNX model files for tests")
}

net := ReadNetFromCaffe(path+"/bvlc_googlenet.prototxt", path+"/bvlc_googlenet.caffemodel")
net := ReadNet(filepath.Join(path, "googlenet-9.onnx"), "")
if net.Empty() {
t.Errorf("Unable to load Caffe model")
t.Errorf("Unable to load ONNX model using ReadNet")
}
defer net.Close()

checkCaffeNet(t, net)
checkONNXNet(t, net)
}

func TestCaffeMemory(t *testing.T) {
path := os.Getenv("GOCV_CAFFE_TEST_FILES")
func TestReadNetMemoryFromONNX(t *testing.T) {
path := os.Getenv("GOCV_ONNX_TEST_FILES")
if path == "" {
t.Skip("Unable to locate Caffe model files for tests")
t.Skip("Unable to locate ONNX model files for tests")
}

_, err := ReadNetFromCaffeBytes(nil, nil)
if err == nil {
t.Errorf("Should have error for reading nil model bytes")
}

bPrototxt, err := ioutil.ReadFile(path + "/bvlc_googlenet.prototxt")
bModel, err := os.ReadFile(filepath.Join(path, "googlenet-9.onnx"))
if err != nil {
t.Errorf("Failed to load Caffe prototxt from file: %v", err)
t.Errorf("Failed to load model from file: %v", err)
}

_, err = ReadNetFromCaffeBytes(bPrototxt, nil)
_, err = ReadNetBytes("onnx", nil, nil)
if err == nil {
t.Errorf("Should have error for reading nil config bytes")
t.Errorf("Should have error for reading nil model bytes")
}

bCaffeModel, err := ioutil.ReadFile(path + "/bvlc_googlenet.caffemodel")
net, err := ReadNetBytes("onnx", bModel, nil)
if err != nil {
t.Errorf("Failed to load Caffe caffemodel from file: %v", err)
}
net, err := ReadNetFromCaffeBytes(bPrototxt, bCaffeModel)
if err != nil {
t.Errorf("Error reading caffe from bytes: %v", err)
t.Errorf("Failed to read net bytes: %v", err)
}
if net.Empty() {
t.Errorf("Unable to load Caffe model")
t.Errorf("Unable to load Caffe model using ReadNetBytes")
}
defer net.Close()

checkCaffeNet(t, net)
checkONNXNet(t, net)
}

func checkTensorflowNet(t *testing.T, net Net) {
Expand Down Expand Up @@ -294,7 +150,7 @@ func TestTensorflowMemory(t *testing.T) {
t.Skip("Unable to locate Tensorflow model file for tests")
}

b, err := ioutil.ReadFile(path + "/tensorflow_inception_graph.pb")
b, err := os.ReadFile(path + "/tensorflow_inception_graph.pb")
if err != nil {
t.Errorf("Failed to load tensorflow model from file: %v", err)
}
Expand All @@ -316,7 +172,7 @@ func TestOnnxMemory(t *testing.T) {
t.Skip("Unable to locate ONNX model file for tests")
}

b, err := ioutil.ReadFile(filepath.Join(path, "googlenet-9.onnx"))
b, err := os.ReadFile(filepath.Join(path, "googlenet-9.onnx"))
if err != nil {
t.Errorf("Failed to load ONNX from file: %v", err)
}
Expand Down
Loading