码迷,mamicode.com
首页 > 其他好文 > 详细

YOLO image结构体操作学习

时间:2016-04-29 17:53:48      阅读:1879      评论:0      收藏:0      [点我收藏+]

标签:

image结构体定义

注意:里面有些代码跟原始的代码有点不一样,比如说class与classes是因为作者将yolo装成window vs下使用的,为了避免以后使用c++时候与类(class),就将源码里面的class统一改为classes。

typedef struct {
    int h;
    int w;
    int c;
    float *data;
} image;
注意:这里data的数据存储是
for c
    for h
        for w

        end
    end
end

image的操作

float get_color(int c, int x, int max)
{//这个函数是为了实现颜色的获取,使用的地方是在 draw_detections 中
    float ratio = ((float)x/max)*5;
    int i = floor(ratio);
    int j = ceil(ratio);
    ratio -= i;
    float r = (1-ratio) * colors[i][c] + ratio*colors[j][c];
    return r;
}

void flip_image(image a)
{//这个函数实现的是image额翻转(翻转的是根据a.w中心来进行的)
    int i,j,k;
    for(k = 0; k < a.c; ++k){
        for(i = 0; i < a.h; ++i){
            for(j = 0; j < a.w/2; ++j){
                int index = j + a.w*(i + a.h*(k));
                int flip = (a.w - j - 1) + a.w*(i + a.h*(k));
                //index 和 flip 是进行调换的位置
                float swap = a.data[flip];
                a.data[flip] = a.data[index];
                a.data[index] = swap;
            }
        }
    }
}
void draw_box(image a, int x1, int y1, int x2, int y2, float r, float g, float b)
{
    int i;
    //下面的操作是进行框边界的界定
    if(x1 < 0) x1 = 0;
    if(x1 >= a.w) x1 = a.w-1;
    if(x2 < 0) x2 = 0;
    if(x2 >= a.w) x2 = a.w-1;

    if(y1 < 0) y1 = 0;
    if(y1 >= a.h) y1 = a.h-1;
    if(y2 < 0) y2 = 0;
    if(y2 >= a.h) y2 = a.h-1;
    //画的是上下两条线
    for(i = x1; i <= x2; ++i){
        a.data[i + y1*a.w + 0*a.w*a.h] = r;
        a.data[i + y2*a.w + 0*a.w*a.h] = r;

        a.data[i + y1*a.w + 1*a.w*a.h] = g;
        a.data[i + y2*a.w + 1*a.w*a.h] = g;

        a.data[i + y1*a.w + 2*a.w*a.h] = b;
        a.data[i + y2*a.w + 2*a.w*a.h] = b;
    }
    //画的是左右两条线
    for(i = y1; i <= y2; ++i){
        a.data[x1 + i*a.w + 0*a.w*a.h] = r;
        a.data[x2 + i*a.w + 0*a.w*a.h] = r;

        a.data[x1 + i*a.w + 1*a.w*a.h] = g;
        a.data[x2 + i*a.w + 1*a.w*a.h] = g;

        a.data[x1 + i*a.w + 2*a.w*a.h] = b;
        a.data[x2 + i*a.w + 2*a.w*a.h] = b;
    }
}
void draw_box_width(image a, int x1, int y1, int x2, int y2, int w, float r, float g, float b)
{//这个函数是实现画宽度为w的矩形框,这个宽度是往里面画,不是往外画
    int i;
    for(i = 0; i < w; ++i){
        draw_box(a, x1+i, y1+i, x2-i, y2-i, r, g, b);
    }
}
void draw_bbox(image a, box bbox, int w, float r, float g, float b)
{//画box需要知道左上角的点和右下角的点
    int left  = (bbox.x-bbox.w/2)*a.w;
    int right = (bbox.x+bbox.w/2)*a.w;
    int top   = (bbox.y-bbox.h/2)*a.h;
    int bot   = (bbox.y+bbox.h/2)*a.h;
    //这个是实现画宽度为w的框
    int i;
    for(i = 0; i < w; ++i){
        draw_box(a, left+i, top+i, right-i, bot-i, r, g, b);
    }
}
void draw_detections(image im, int num, float thresh, box *boxes, float **probs, char **names, image *labels, int classes)
{//classes是类别数,probs是num*classes的数组
    int i;
    for(i = 0; i < num; ++i){
        int class = max_index(probs[i], classes);//这个函数返回最大的值的index,也就是对应的是bbox对应的类别。
        float prob = probs[i][class];
        if(prob > thresh){//超过阈值后才会画bbox
            int width = pow(prob, 1./2.)*10+1;//这个是用于画框的宽度和label用的宽度
            printf("%s: %.2f\n", names[class], prob);
            //颜色
            int offset = class*17 % classes;
            float red = get_color(0,offset,classes);
            float green = get_color(1,offset,classes);
            float blue = get_color(2,offset,classes);
            float rgb[3];
            rgb[0] = red;
            rgb[1] = green;
            rgb[2] = blue;

            box b = boxes[i];

            int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;
            int bot   = (b.y+b.h/2.)*im.h;

            if(left < 0) left = 0;
            if(right > im.w-1) right = im.w-1;
            if(top < 0) top = 0;
            if(bot > im.h-1) bot = im.h-1;
            draw_box_width(im, left, top, right, bot, width, red, green, blue);
            if (labels) draw_label(im, top + width, left, labels[class], rgb);
        }
    }
}
image image_distance(image a, image b)
{//返回一个通道为1的image,相对应点的欧拉距离。
    int i,j;
    image dist = make_image(a.w, a.h, 1);
    for(i = 0; i < a.c; ++i){
        for(j = 0; j < a.h*a.w; ++j){
            dist.data[j] += pow(a.data[i*a.h*a.w+j]-b.data[i*a.h*a.w+j],2);
        }
    }
    for(j = 0; j < a.h*a.w; ++j){
        dist.data[j] = sqrt(dist.data[j]);
    }
    return dist;
}
void scale_image(image m, float s)
{// 函数的功能iamge = image * s
     int i;
     for(i = 0; i < m.h*m.w*m.c; ++i) m.data[i] *= s;
}
    image crop_image(image im, int dx, int dy, int w, int h)
    {//函数的功能获取im里面的区域,偏移为dx,dy,宽高为w,h
        image cropped = make_image(w, h, im.c);//这个函数返回image类型,初始化化都为0,使用的是calloc(这个函数可以初始化,而malloc没有初始化功能)
        int i, j, k;
        for(k = 0; k < im.c; ++k){
            for(j = 0; j < h; ++j){
                for(i = 0; i < w; ++i){
                    int r = j + dy;
                    int c = i + dx;
                    float val = 0;
                    if (r >= 0 && r < im.h && c >= 0 && c < im.w) {
                        val = get_pixel(im, c, r, k);
                    }
                    set_pixel(cropped, i, j, k, val);
                }
            }
        }
        return cropped;
    }
    image random_crop_image(image im, int low, int high, int size)
    {//返回大小为size*size的随机crop
        int r = rand_int(low, high);//随机返回[low,hight]之间的之值
        image resized = resize_min(im, r);//min(w,h)被调节为r
        int dx = rand_int(0, resized.w - size);//这样设置是为了保证crop的偏移量不会越界 
        int dy = rand_int(0, resized.h - size);
        image crop = crop_image(resized, dx, dy, size, size);
        free_image(resized);
        return crop;
    }
     image resize_image(image im, int w, int h)
    {//实现resize的功能
        image resized = make_image(w, h, im.c);   
        image part = make_image(w, im.h, im.c);
        int r, c, k;
        float w_scale = (float)(im.w - 1) / (w - 1);
        float h_scale = (float)(im.h - 1) / (h - 1);
        for(k = 0; k < im.c; ++k){
            for(r = 0; r < im.h; ++r){
                for(c = 0; c < w; ++c){
                    float val = 0;
                    if(c == w-1 || im.w == 1){//这两种情况,可能会出现get_pixel获得越界的数值
                        val = get_pixel(im, im.w-1, r, k);
                    } else {
                        float sx = c*w_scale;
                        int ix = (int) sx;
                        float dx = sx - ix;
                        val = (1 - dx) * get_pixel(im, ix, r, k) + dx * get_pixel(im, ix+1, r, k);
                    }
                    set_pixel(part, c, r, k, val);
                }
            }
        }
        for(k = 0; k < im.c; ++k){
            for(r = 0; r < h; ++r){
            //这个地方觉得怪,这个地方变化应该是跟上面的一样,作者这个地方不一致只是在r == h-1或者im.h == 1的情况乘(1-dy)
                float sy = r*h_scale;
                int iy = (int) sy;
                float dy = sy - iy;
                for(c = 0; c < w; ++c){
                    float val = (1-dy) * get_pixel(part, c, iy, k);
                    set_pixel(resized, c, r, k, val);
                }
                if(r == h-1 || im.h == 1) continue;
                for(c = 0; c < w; ++c){
                    float val = dy * get_pixel(part, c, iy+1, k);
                    add_pixel(resized, c, r, k, val);
                }
            }
        }
        free_image(part);
        return resized;
    }
    image resize_min(image im, int min)
    {//这个函数是实现将im的w,h两个最小值设置为min,然后根据比例调节大的那个值。
    //$\dfrac{max(w,h)}{t} = \dfrac{min(w,h)}{min}$
        int w = im.w;
        int h = im.h;
        if(w < h){
            h = (h * min) / w;
            w = min;
        } else {
            w = (w * min) / h;
            h = min;
        }
        image resized = resize_image(im, w, h);
        return resized;
    }
    void translate_image(image m, float s)
    {//像素点全部加s
        int i;
        for(i = 0; i < m.h*m.w*m.c; ++i) m.data[i] += s;
    }

void normalize_image(image p)
{
    float *min = calloc(p.c, sizeof(float));
    float *max = calloc(p.c, sizeof(float));
    int i,j;
    //用每个通道的第一个值来初始化每个通道的最大值和最小值
    for(i = 0; i < p.c; ++i) min[i] = max[i] = p.data[i*p.h*p.w];
    for(j = 0; j < p.c; ++j){//获取每个通道的最大值和最小值
        for(i = 0; i < p.h*p.w; ++i){
        //我认为这个地方i的取值可以从1开始,因为已经用了第一个值进行赋值了
            float v = p.data[i+j*p.h*p.w];
            if(v < min[j]) min[j] = v;
            if(v > max[j]) max[j] = v;
        }
    }
    for(i = 0; i < p.c; ++i){
        if(max[i] - min[i] < .000000001){
            min[i] = 0;
            max[i] = 1;
        }
    }
    for(j = 0; j < p.c; ++j){
        for(i = 0; i < p.w*p.h; ++i){//归一化操作
            p.data[i+j*p.h*p.w] = (p.data[i+j*p.h*p.w] - min[j])/(max[j]-min[j]);
        }
    }
    free(min);
    free(max);
}
    image rotate_image(image im, float rad)
    {//这个函数实现image按照中心点矩阵旋转(逆时针旋转rad这个是弧度,转化是rad*3.14/180)旋转矩阵在最下面有图示
        int x, y, c;
        float cx = im.w/2.;
        float cy = im.h/2.;
        image rot = make_image(im.w, im.h, im.c);
        for(c = 0; c < im.c; ++c){
            for(y = 0; y < im.h; ++y){
                for(x = 0; x < im.w; ++x){
                    //先将点平移到(0,0)点,然后旋转,后再平移回去
                    float rx = cos(rad)*(x-cx) - sin(rad)*(y-cy) + cx;
                    float ry = sin(rad)*(x-cx) + cos(rad)*(y-cy) + cy;
                    float val = bilinear_interpolate(im, rx, ry, c);//双线性插值函数,双线性插值示意图在最下面
                    set_pixel(rot, x, y, c, val);
                }
            }
        }
        return rot;
    }
void rotate_image_cw(image im, int times)
{//实现的是逆时针旋转times次90度
    assert(im.w == im.h);
    times = (times + 400) % 4;
    int i, x, y, c;
    int n = im.w;
    for(i = 0; i < times; ++i){
        for(c = 0; c < im.c; ++c){
            for(x = 0; x < n/2; ++x){
                for(y = 0; y < (n-1)/2 + 1; ++y){
                    float temp = im.data[y + im.w*(x + im.h*c)];
                    im.data[y + im.w*(x + im.h*c)] = im.data[n-1-x + im.w*(y + im.h*c)];
                    im.data[n-1-x + im.w*(y + im.h*c)] = im.data[n-1-y + im.w*(n-1-x + im.h*c)];
                    im.data[n-1-y + im.w*(n-1-x + im.h*c)] = im.data[x + im.w*(n-1-y + im.h*c)];
                    im.data[x + im.w*(n-1-y + im.h*c)] = temp;
                }
            }
        }
    }
}
void embed_image(image source, image dest, int dx, int dy)
{// 该函数实现的是将source平移dx,dy然后赋值给dest
    int x,y,k;
    for(k = 0; k < source.c; ++k){
        for(y = 0; y < source.h; ++y){
            for(x = 0; x < source.w; ++x){
                float val = get_pixel(source, x,y,k);
                set_pixel(dest, dx+x, dy+y, k, val);
            }
        }
    }
}
/*/还没
void saturate_image(image im, float sat);
void exposure_image(image im, float sat);
void saturate_exposure_image(image im, float sat, float exposure);
void hsv_to_rgb(image im);
void rgbgr_image(image im);
void constrain_image(image im);
*/
    image grayscale_image(image im)
    {
        assert(im.c == 3);
        int i, j, k;
        image gray = make_image(im.w, im.h, 1);
        float scale[] = {0.587, 0.299, 0.114};
        //根据这个系数转化
        for(k = 0; k < im.c; ++k){
            for(j = 0; j < im.h; ++j){
                for(i = 0; i < im.w; ++i){
                    gray.data[i+im.w*j] += scale[k]*get_pixel(im, i, j, k);
                }
            }
        }
        return gray;
    }
    image threshold_image(image im, float thresh)
    {
        int i;
        image t = make_image(im.w, im.h, im.c);
        for(i = 0; i < im.w*im.h*im.c; ++i){
            t.data[i] = im.data[i]>thresh ? 1 : 0;
        }
        return t;
    }
/*/不在image.c中
image collapse_image_layers(image source, int border);
image collapse_images_horz(image *ims, int n);
image collapse_images_vert(image *ims, int n);
*/

显示image的操作
void show_image(image p, const char *name);
void show_image_normalized(image im, const char *name);
void save_image(image p, const char *name);
void show_images(image *ims, int n, char *window);
void show_image_layers(image p, char *name);
void show_image_collapsed(image p, char *name);

编译有OPENCV时候进行的操作
#ifdef OPENCV
void save_image_jpg(image p, char *name);
image get_image_from_stream(CvCapture *cap);
image ipl_to_image(IplImage* src);
#endif

输出image
void print_image(image m);

image初始化,赋值的操作
image make_image(int w, int h, int c);
image make_random_image(int w, int h, int c);
image make_empty_image(int w, int h, int c);
image float_to_image(int w, int h, int c, float *data);
image copy_image(image p);
image load_image(char *filename, int w, int h, int c);
image load_image_color(char *filename, int w, int h);

image像素的操作
float get_pixel(image m, int x, int y, int c);
float get_pixel_extend(image m, int x, int y, int c);
void set_pixel(image m, int x, int y, int c, float val);
void add_pixel(image m, int x, int y, int c, float val);
float bilinear_interpolate(image im, float x, float y, int c);

从层获取image
image get_image_layer(image m, int l);

释放image
void free_image(image m);

测试resize
void test_resize(char *filename);

技术分享
双线性插值示意图,这里可以这样理解,当dx,越小左边点的贡献比较大,同理dy也是这样。

技术分享
旋转矩阵

YOLO image结构体操作学习

标签:

原文地址:http://blog.csdn.net/u012235274/article/details/51253947

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!