标签:
注意:里面有些代码跟原始的代码有点不一样,比如说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
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也是这样。
旋转矩阵
标签:
原文地址:http://blog.csdn.net/u012235274/article/details/51253947