From e51289b772ca50ff7542ba488a72bb53334f0f89 Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Sun, 3 Apr 2022 15:21:07 +0200 Subject: [PATCH] first attempt to measure the level --- getvideo.c | 31 ++++++++++++++++++ image.c | 22 +++++++++++++ main.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++-- vidoiltank.h | 7 +++- 4 files changed, 148 insertions(+), 4 deletions(-) diff --git a/getvideo.c b/getvideo.c index 36b4e02..243a18d 100644 --- a/getvideo.c +++ b/getvideo.c @@ -91,6 +91,8 @@ Video *vid_open(char *name) { } } + vid_getctrls(video); + return video; } @@ -324,3 +326,32 @@ int vid_stop(Video* video) { return 0; }; + +void vid_getctrls (Video* video) { + int i, j; + struct v4l2_queryctrl queryctrl; + memset (&queryctrl, 0, sizeof (queryctrl)); + for (j = 0, i = V4L2_CID_BASE; i < V4L2_CID_DETECT_CLASS_BASE+0x1000; i++) { + queryctrl.id = i; + if (0 == ioctl (video->fd, VIDIOC_QUERYCTRL, &queryctrl)) { + if (j == 0) video->ctrl_bright = queryctrl.id; + else if (j == 1) video->ctrl_contrast = queryctrl.id; + j++; + } + } +}; + + +void vid_setctrls (Video* video, int bright, int contrast) { + struct v4l2_control ctrl; + + CLEAR(ctrl); + ctrl.id = video->ctrl_bright; + ctrl.value = bright; + xioctl (video->fd, VIDIOC_S_CTRL, &ctrl); + + CLEAR(ctrl); + ctrl.id = video->ctrl_contrast; + ctrl.value = contrast; + xioctl (video->fd, VIDIOC_S_CTRL, &ctrl); +}; diff --git a/image.c b/image.c index 21478f1..a390ec1 100644 --- a/image.c +++ b/image.c @@ -135,6 +135,28 @@ void image_draw_rect (ImageRaw *img, Rect *r, int col) { } +void image_get_minmax (ImageRaw *img, Rect *r, int *min, int *max) { + int x, y, l, cr, cg, cb; + if (img == NULL || img->data == NULL) return; + + cr = (unsigned char)*(img->data+0+3*(r->x+r->y*img->w)); + cg = (unsigned char)*(img->data+1+3*(r->x+r->y*img->w)); + cb = (unsigned char)*(img->data+2+3*(r->x+r->y*img->w)); + *min = *max = cr + cg + cb; + + for (x = r->x; x < (r->x+r->w) && x < img->w; x++) + for (y = r->y; y < (r->w + r->h) && y < img->h; y++) { + cr = (unsigned char)*(img->data+0+3*(x+y*img->w)); + cg = (unsigned char)*(img->data+1+3*(x+y*img->w)); + cb = (unsigned char)*(img->data+2+3*(x+y*img->w)); +// printf ("%d %d %d\n", cr, cg, cb); + l = cr + cg + cb; + if (l < *min) *min = l; + if (l > *max) *max = l; + } +} + + ImageFloat *imageF_alloc (int w, int h) { ImageFloat *i = NULL; diff --git a/main.c b/main.c index 85ad334..103aecf 100644 --- a/main.c +++ b/main.c @@ -14,6 +14,8 @@ int conf_samples = 25; int conf_rotate = 0; Rect conf_rect = { .x = 315, .y = 0, .w = 70, .h = 1910 }; +int detect_level(ImageFloat *imgf); + /* * open video device * read multiple images into memory @@ -45,7 +47,7 @@ int main(int argc, char **argv) { char outdate[LEN_FILENAME]; time_t curtime = time(NULL); struct tm *curtime_tm = NULL; - int i; + int i, c, b, level, cont, bright, min, max; // for debugging only curtime_tm = localtime(&curtime); @@ -92,9 +94,38 @@ int main(int argc, char **argv) { // printf ("vidoiltank\n"); // printf (" device: %s (%d x %d)\n", conf_devname, conf_width, conf_height); + // + // open video device if ((video = vid_open("/dev/video0")) == NULL) return -1; if (vid_start(video, conf_iomode, conf_width, conf_height) == -1) return -1; + // + // search for god brightness and contrast + printf ("check controls\n"); + cont = 200; // just picked some random numbers + bright = 170; // just picked some random numbers + for (level = 0, c = 32; c <= 250; c += 64) + for (b = 32; b <= 250; b += 64) { + vid_setctrls(video, b, c); + do {} while ((tmpimg = vid_grabimage(video, img)) == NULL && errno == EAGAIN); + if (tmpimg == NULL) { + printf ("could not grab image\n"); + exit(1); + } + img = tmpimg; + image_get_minmax (img, &conf_rect, &min, &max); + if (max-min > level) { + cont = c; + bright = b; + level = max-min; + } + } + printf ("found best control: contrast: %d brightness: %d\n", cont, bright); + vid_setctrls(video, bright, cont); + + // + // get samples + printf ("Read Samples\n"); for (i = 0; i < conf_samples; i++) { do {} while ((tmpimg = vid_grabimage(video, img)) == NULL && errno == EAGAIN); if (tmpimg == NULL) { @@ -110,7 +141,7 @@ int main(int argc, char **argv) { } if (i == 0) { - snprintf (fn, 3*LEN_FILENAME, "%s/%s-img-%02d.jpg", conf_debugout, outdate, i); + snprintf (fn, 3*LEN_FILENAME, "%s/%s-img-%02d-%02d.jpg", conf_debugout, outdate, bright, cont); image_draw_rect(img, &conf_rect, 0x00FFFF); image_save(img, fn, 98); } @@ -123,8 +154,63 @@ int main(int argc, char **argv) { snprintf (fn, 3*LEN_FILENAME, "%s/%s-imgf-%03d.jpg", conf_debugout, outdate, conf_samples); image_save(tmpimg, fn, 98); + level = detect_level(imgf); + tmpimg = image_copyF(imgf); + Rect r = {.x = 0, .y = level, .w = 10, .h = 1}; + image_draw_rect(tmpimg, &r, 0x0000FF00); + snprintf (fn, 3*LEN_FILENAME, "%s/%s-img-data.jpg", conf_debugout, outdate); + image_save(tmpimg, fn, 98); + + printf ("%s Found Level: %5.2f Y-Pos: %d\n", outdate, 100.0 * (1.0-(float)level/(float)imgf->h), level); + return 0; -} +}; + + +int detect_level(ImageFloat *imgf) { + int y, x, ylow, level; + float v = 0.0, vmin, vmax; + + // + // calculate average, and save value in left row + for (y = 0; y < imgf->h; y++) { + for (v = 0.0, x = 0; x < imgf->w; x++) + v += imgf->data[x + y * imgf->w]; + v = v / (float) x; + if (y == 0) vmin = vmax = v; + if (vmin > v) vmin = v; + if (vmax < v) vmax = v; + + // save result in the top left position, + // together with a bar for display + imgf->data[y * imgf->w] = v; + } + // + // normalize 0.0 .. 1.0 + for (y = 0; y < imgf->h; y++) for (x = 0; x < imgf->w; x++) { + imgf->data[x + y * imgf->w] = (imgf->data[x + y * imgf->w]-vmin)/(vmax-vmin); + } + + // + // search for the level from below + vmin = 1.0; + vmax = 0.0; + int avg = 8; + + level = 0; + for (ylow = 0; ylow < imgf->h; ylow++) { + if (ylow == 0) v = imgf->data[(ylow) * imgf->w]; + v = ((float)avg-1.0) * v/(float)avg + imgf->data[(ylow) * imgf->w]/(float) avg; + for (x = 0; x < 8; x++) imgf->data[x + (ylow) * imgf->w] = v; + } + for (ylow = imgf->h - 1; ylow >= 0; ylow--) { + if (ylow == imgf->h - 1) v = imgf->data[(ylow) * imgf->w]; + v = ((float)avg-1.0) * v/(float)avg + imgf->data[(ylow) * imgf->w]/(float) avg; + for (x = 4; x < 16; x++) imgf->data[x + (ylow) * imgf->w] = v; + if (v < 0.1) level = ylow; + } + return level; +}; diff --git a/vidoiltank.h b/vidoiltank.h index e6edaee..09deab9 100644 --- a/vidoiltank.h +++ b/vidoiltank.h @@ -74,6 +74,9 @@ struct s_video { struct v4l2_crop crop; struct v4l2_format fmt; + unsigned int ctrl_bright; + unsigned int ctrl_contrast; + } typedef Video; @@ -104,6 +107,7 @@ ImageFloat *imageF_alloc (int w, int h); ImageFloat *imageF_copy(ImageRaw *iraw, Rect *r); ImageRaw *image_copyF(ImageFloat *ifloat); void imageF_add(ImageFloat *ifloat, ImageRaw *iraw, Rect *r); +void image_get_minmax (ImageRaw *img, Rect *r, int *min, int *max); /* getvideo.c * @@ -115,6 +119,7 @@ int vid_start(Video* video, int ionmode, int width, int height); ImageRaw *vid_grabimage(Video* video, ImageRaw *img); int vid_stop(Video* video); void vid_close(Video* video); - +void vid_getctrls (Video* video); +void vid_setctrls (Video* video, int bright, int contrast); #endif