| @@ -23,8 +23,12 @@ · 22 unmodified lines |
| 23 | * libopencv wrapper functions | 23 | * libopencv wrapper functions |
| 24 | */ | 24 | */ |
| 25 | | 25 | |
| | 26 | /* #define DEBUG */ |
| | 27 | |
| 26 | #include <opencv/cv.h> | 28 | #include <opencv/cv.h> |
| 27 | #include <opencv/cxtypes.h> | 29 | #include <opencv/cxtypes.h> |
| | 30 | #include "libavutil/avstring.h" |
| | 31 | #include "libavutil/file.h" |
| 28 | #include "avfilter.h" | 32 | #include "avfilter.h" |
| 29 | | 33 | |
| 30 | static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum PixelFormat pixfmt) | 34 | static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum PixelFormat pixfmt) |
| @@ -127,6 +131,166 @@ static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplIm · 96 unmodified lines |
| 127 | cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4); | 131 | cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4); |
| 128 | } | 132 | } |
| 129 | | 133 | |
| | 134 | static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename, |
| | 135 | void *log_ctx) |
| | 136 | { |
| | 137 | uint8_t *buf, *p, *pend; |
| | 138 | size_t size; |
| | 139 | int ret, i, j, w; |
| | 140 | |
| | 141 | if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0) |
| | 142 | return ret; |
| | 143 | |
| | 144 | /* prescan file to get the number of lines and the maximum width */ |
| | 145 | w = 0; |
| | 146 | for (i = 0; i < size; i++) { |
| | 147 | if (buf[i] == '\n') { |
| | 148 | if (*rows == INT_MAX) { |
| | 149 | av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n"); |
| | 150 | return AVERROR_INVALIDDATA; |
| | 151 | } |
| | 152 | ++(*rows); |
| | 153 | *cols = FFMAX(*cols, w); |
| | 154 | w = 0; |
| | 155 | } else if (w == INT_MAX) { |
| | 156 | av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n"); |
| | 157 | return AVERROR_INVALIDDATA; |
| | 158 | } |
| | 159 | w++; |
| | 160 | } |
| | 161 | if (*rows > (FF_INTERNAL_MEM_TYPE_MAX_VALUE / (sizeof(int)) / *cols)) { |
| | 162 | av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n", |
| | 163 | *rows, *cols); |
| | 164 | return AVERROR_INVALIDDATA; |
| | 165 | } |
| | 166 | if (!(*values = av_mallocz(sizeof(int) * *rows * *cols))) |
| | 167 | return AVERROR(ENOMEM); |
| | 168 | |
| | 169 | /* fill *values */ |
| | 170 | p = buf; |
| | 171 | pend = buf + size-1; |
| | 172 | for (i = 0; i < *rows; i++) { |
| | 173 | for (j = 0;; j++) { |
| | 174 | if (p > pend || *p == '\n') { |
| | 175 | p++; |
| | 176 | break; |
| | 177 | } else |
| | 178 | (*values)[*cols*i + j] = !!isgraph(*(p++)); |
| | 179 | } |
| | 180 | } |
| | 181 | av_file_unmap(buf, size); |
| | 182 | |
| | 183 | #ifdef DEBUG |
| | 184 | { |
| | 185 | char *line; |
| | 186 | if (!(line = av_malloc(*cols + 1))) |
| | 187 | return AVERROR(ENOMEM); |
| | 188 | for (i = 0; i < *rows; i++) { |
| | 189 | for (j = 0; j < *cols; j++) |
| | 190 | line[j] = (*values)[i * *cols + j] ? '@' : ' '; |
| | 191 | line[j] = 0; |
| | 192 | av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line); |
| | 193 | } |
| | 194 | av_free(line); |
| | 195 | } |
| | 196 | #endif |
| | 197 | |
| | 198 | return 0; |
| | 199 | } |
| | 200 | |
| | 201 | static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx) |
| | 202 | { |
| | 203 | char shape_filename[128] = "", shape_str[32] = "rect"; |
| | 204 | int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT; |
| | 205 | int *values = NULL, ret; |
| | 206 | |
| | 207 | sscanf(buf, "%dx%d+%dx%d/%32[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename); |
| | 208 | |
| | 209 | if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT; |
| | 210 | else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS; |
| | 211 | else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE; |
| | 212 | else if (!strcmp(shape_str, "custom" )) { |
| | 213 | shape = CV_SHAPE_CUSTOM; |
| | 214 | if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0) |
| | 215 | return ret; |
| | 216 | } else { |
| | 217 | av_log(log_ctx, AV_LOG_ERROR, |
| | 218 | "Shape unspecified or type '%s' unknown\n.", shape_str); |
| | 219 | return AVERROR(EINVAL); |
| | 220 | } |
| | 221 | |
| | 222 | if (rows <= 0 || cols <= 0) { |
| | 223 | av_log(log_ctx, AV_LOG_ERROR, |
| | 224 | "Invalid non-positive values for shape size %dx%d\n", cols, rows); |
| | 225 | return AVERROR(EINVAL); |
| | 226 | } |
| | 227 | |
| | 228 | if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) { |
| | 229 | av_log(log_ctx, AV_LOG_ERROR, |
| | 230 | "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n", |
| | 231 | anchor_x, anchor_y, cols, rows); |
| | 232 | return AVERROR(EINVAL); |
| | 233 | } |
| | 234 | |
| | 235 | *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values); |
| | 236 | av_freep(&values); |
| | 237 | if (!*kernel) |
| | 238 | return AVERROR(ENOMEM); |
| | 239 | |
| | 240 | av_log(log_ctx, AV_LOG_INFO, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n", |
| | 241 | rows, cols, anchor_x, anchor_y, shape_str); |
| | 242 | return 0; |
| | 243 | } |
| | 244 | |
| | 245 | typedef struct { |
| | 246 | int nb_iterations; |
| | 247 | IplConvKernel *kernel; |
| | 248 | } DilateContext; |
| | 249 | |
| | 250 | static av_cold int dilate_init(AVFilterContext *ctx, const char *args, void *opaque) |
| | 251 | { |
| | 252 | OCVContext *ocv = ctx->priv; |
| | 253 | DilateContext *dilate = ocv->priv; |
| | 254 | char default_kernel_str[] = "3x3+0x0/rect"; |
| | 255 | char *kernel_str; |
| | 256 | const char *buf = args; |
| | 257 | int ret; |
| | 258 | |
| | 259 | dilate->nb_iterations = 1; |
| | 260 | |
| | 261 | if (args) |
| | 262 | kernel_str = av_get_token(&buf, ":"); |
| | 263 | if ((ret = parse_iplconvkernel(&dilate->kernel, |
| | 264 | *kernel_str ? kernel_str : default_kernel_str, |
| | 265 | ctx)) < 0) |
| | 266 | return ret; |
| | 267 | av_free(kernel_str); |
| | 268 | |
| | 269 | sscanf(buf, ":%d", &dilate->nb_iterations); |
| | 270 | av_log(ctx, AV_LOG_INFO, "iterations_nb:%d\n", dilate->nb_iterations); |
| | 271 | if (dilate->nb_iterations <= 0) { |
| | 272 | av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n", |
| | 273 | dilate->nb_iterations); |
| | 274 | return AVERROR(EINVAL); |
| | 275 | } |
| | 276 | return 0; |
| | 277 | } |
| | 278 | |
| | 279 | static av_cold void dilate_uninit(AVFilterContext *ctx) |
| | 280 | { |
| | 281 | OCVContext *ocv = ctx->priv; |
| | 282 | DilateContext *dilate = ocv->priv; |
| | 283 | |
| | 284 | cvReleaseStructuringElement(&dilate->kernel); |
| | 285 | } |
| | 286 | |
| | 287 | static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg) |
| | 288 | { |
| | 289 | OCVContext *ocv = ctx->priv; |
| | 290 | DilateContext *dilate = ocv->priv; |
| | 291 | cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations); |
| | 292 | } |
| | 293 | |
| 130 | typedef struct { | 294 | typedef struct { |
| 131 | const char *name; | 295 | const char *name; |
| 132 | size_t priv_size; | 296 | size_t priv_size; |
| @@ -136,6 +300,7 @@ typedef struct { · 3 unmodified lines |
| 136 | } OCVFilterEntry; | 300 | } OCVFilterEntry; |
| 137 | | 301 | |
| 138 | static OCVFilterEntry ocv_filter_entries[] = { | 302 | static OCVFilterEntry ocv_filter_entries[] = { |
| | 303 | { "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter }, |
| 139 | { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter }, | 304 | { "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter }, |
| 140 | }; | 305 | }; |
| 141 | | 306 | |