【CV源码实现及调试】darknet中opencv的问题

error

./src/image_opencv.cpp:5:10: fatal error: opencv2/opencv.hpp: No such file or directory
    5 | #include "opencv2/opencv.hpp"

error

./src/image_opencv.cpp:12:1: error: ‘IplImage’ does not name a type
   12 | IplImage *image_to_ipl(image im)

问题原因,说到底就是opencv include和lib的路径问题;

 

安装opencv

使用cmake安装,编译阶段会出现问题,或者编译安装成功,但是没有opencv_world库,最后直接使用cmake gui安装;

解决方法:

重新安装opencv,修改Makefile中opencv部分,然后更改src/image_opencv.cpp文件,使用Mat替换IplImage,且 remove all CV_ from opencv flags
 
sudo apt install libopencv-dev  # opencv 4.2.0
dpkg --list | grep opencv
pkg-config --libs opencv4
pkg-config --cflags opencv4

Makefile

LDFLAGS+= `pkg-config --libs opencv4` -lstdc++
COMMON+= `pkg-config --cflags opencv4`

src/image_opencv.cpp

#ifdef OPENCV

#include "stdio.h"
#include "stdlib.h"
#include "opencv2/opencv.hpp"
#include "image.h"

using namespace cv;

extern "C" {
// /*
Mat image_to_mat(image im)
{
    image copy = copy_image(im);
    constrain_image(copy);
    if(im.c == 3) rgbgr_image(copy);
    
    Mat m(cv::Size(im.w,im.h), CV_8UC(im.c));
    int x,y,c;
    
    int step = m.step;
    for(y = 0; y < im.h; ++y){
        for(x = 0; x < im.w; ++x){
            for(c= 0; c < im.c; ++c){
                float val = im.data[c*im.h*im.w + y*im.w + x];
                m.data[y*step + x*im.c + c] = (unsigned char)(val*255);
            }
        }
    }
    
    free_image(copy);
    return m;

}

image mat_to_image(Mat m)
{
    int h = m.rows;
    int w = m.cols;
    int c = m.channels();
    image im = make_image(w, h, c);
    unsigned char *data = (unsigned char *)m.data;
    int step = m.step;
    int i, j, k;
    
    for(i = 0; i < h; ++i){
        for(k= 0; k < c; ++k){
            for(j = 0; j < w; ++j){
                im.data[k*w*h + i*w + j] = data[i*step + j*c + k]/255.;
            }
        }
    }
    rgbgr_image(im);
    return im;
}

/*
IplImage *image_to_ipl(image im)
{
    int x,y,c;
    IplImage *disp = cvCreateImage(cvSize(im.w,im.h), IPL_DEPTH_8U, im.c);
    int step = disp->widthStep;
    for(y = 0; y < im.h; ++y){
        for(x = 0; x < im.w; ++x){
            for(c= 0; c < im.c; ++c){
                float val = im.data[c*im.h*im.w + y*im.w + x];
                disp->imageData[y*step + x*im.c + c] = (unsigned char)(val*255);
            }
        }
    }
    return disp;
}

image ipl_to_image(IplImage* src)
{
    int h = src->height;
    int w = src->width;
    int c = src->nChannels;
    image im = make_image(w, h, c);
    unsigned char *data = (unsigned char *)src->imageData;
    int step = src->widthStep;
    int i, j, k;

    for(i = 0; i < h; ++i){
        for(k= 0; k < c; ++k){
            for(j = 0; j < w; ++j){
                im.data[k*w*h + i*w + j] = data[i*step + j*c + k]/255.;
            }
        }
    }
    return im;
}

Mat image_to_mat(image im)
{
    image copy = copy_image(im);
    constrain_image(copy);
    if(im.c == 3) rgbgr_image(copy);

    IplImage *ipl = image_to_ipl(copy);
    Mat m = cvarrToMat(ipl, true);
    cvReleaseImage(&ipl);
    free_image(copy);
    return m;
}

image mat_to_image(Mat m)
{
    IplImage ipl = m;
    image im = ipl_to_image(&ipl);
    rgbgr_image(im);
    return im;
}
*/
// 
void *open_video_stream(const char *f, int c, int w, int h, int fps)
{
    VideoCapture *cap;
    if(f) cap = new VideoCapture(f);
    else cap = new VideoCapture(c);
    if(!cap->isOpened()) return 0;
    if(w) cap->set(CAP_PROP_FRAME_WIDTH, w);
    if(h) cap->set(CAP_PROP_FRAME_HEIGHT, w);
    if(fps) cap->set(CAP_PROP_FPS, w);
    return (void *) cap;
}

image get_image_from_stream(void *p)
{
    VideoCapture *cap = (VideoCapture *)p;
    Mat m;
    *cap >> m;
    if(m.empty()) return make_empty_image(0,0,0);
    return mat_to_image(m);
}

image load_image_cv(char *filename, int channels)
{
    int flag = -1;
    if (channels == 0) flag = -1;
    else if (channels == 1) flag = 0;
    else if (channels == 3) flag = 1;
    else {
        fprintf(stderr, "OpenCV can't force load with %d channels\n", channels);
    }
    Mat m;
    m = imread(filename, flag);
    if(!m.data){
        fprintf(stderr, "Cannot load image \"%s\"\n", filename);
        char buff[256];
        sprintf(buff, "echo %s >> bad.list", filename);
        system(buff);
        return make_image(10,10,3);
        //exit(0);
    }
    image im = mat_to_image(m);
    return im;
}

int show_image_cv(image im, const char* name, int ms)
{
    Mat m = image_to_mat(im);
    imshow(name, m);
    int c = waitKey(ms);
    if (c != -1) c = c%256;
    return c;
}

void make_window(char *name, int w, int h, int fullscreen)
{
    namedWindow(name, WINDOW_NORMAL); 
    if (fullscreen) {
        setWindowProperty(name, WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
    } else {
        resizeWindow(name, w, h);
        if(strcmp(name, "Demo") == 0) moveWindow(name, 0, 0);
    }
}

}

#endif
View Code

first isntall opencv,
sudo apt install libopencv-dev
then modify Makefile and src/image_opencv.cpp, including replace IplImage with Mat, and remove all CV_ from opencv flags.

代码理解

float val = im.data[c*im.h*im.w + y*im.w + x];   
m.data[y*step + x*im.c + c] = (unsigned char)(val*255);
or
im.data[k*w*h + i*w + j] = data[i*step + j*c + k]/255.;

主要是对 y*step + x*im.c + c的理解,没明白。。

update 20220809

之后发现这个和数据排列存放形式有关;

opencv中cv::Mat的排列存放方式如下图所示,通常情况下Mat的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,在用指针访问时可以提供很大方便。

感觉opencv和STBI图像库中的图像数据都是这样排列存储的,不过opencv是BGR而STBI是RGB;

而darknet中image数据类型的存放方式是一个通道一个通道的存放的,详见src/image.c.

image load_image_stb(char *filename, int channels)
{
    int w, h, c;
    unsigned char *data = stbi_load(filename, &w, &h, &c, channels);
    if (!data) {
        fprintf(stderr, "Cannot load image \"%s\"\nSTB Reason: %s\n", filename, stbi_failure_reason());
        exit(0);
    }
    if(channels) c = channels;
    int i,j,k;
    image im = make_image(w, h, c);
    for(k = 0; k < c; ++k){
        for(j = 0; j < h; ++j){
            for(i = 0; i < w; ++i){
                int dst_index = i + w*j + w*h*k;
                int src_index = k + c*i + c*w*j;
                im.data[dst_index] = (float)data[src_index]/255.;
            }
        }
    }
    free(data);
    return im;
}

 这次分析是因为遇到问题,就是图像显示的颜色有点不对,比如黄色的显示的却是蓝色,感觉这个可能是和赋值的index有关,而且保存图像颜色正常,只是显示的时候不对。。。。之前测试没发现这个问题呀,不知道是一直就有还是现在才有这个问题。。

之后发现是通道转换过程的细节问题,修改src/image_opencv.cpp中的一条语句即可;

将 image_to_mat函数中的

float val = im.data[c*im.h*im.w + y*im.w + x];

替换为

float val = copy.data[c*im.h*im.w + y*im.w + x];

 

参考

1. github_issue

2. opencv-how-image-stored-memory

 

posted on 2022-07-25 18:42  鹅要长大  阅读(446)  评论(0编辑  收藏  举报

导航