bool QxPotrace::trace(const QImage &image) { QElapsedTimer timer; timer.start(); potrace_bitmap_t *bitmap = bitmapFromImage(image, m_threshold); potrace_param_t *params = potrace_param_default(); params->alphamax = m_alphaMax; params->opttolerance = m_curveTolerance; params->turdsize = m_turdSize; // params->progress.callback = &Tracer::progress; potrace_state_t *st = potrace_trace(params, bitmap); bm_free(bitmap); potrace_param_free(params); if(!st || st->status != POTRACE_STATUS_OK) return false; m_meshDefs = tracedPolygonsFromPath(st->plist, m_bezierPrecision); potrace_state_free(st); return true; }
/* 二值图像矢量化(该方法会矢量化图像的外轮廓和内轮廓) * binaryImageData 二值图像数据 */ potrace_state_t* binaryToVector(IplImage* binaryImageData) { /**********将二值灰度图转换成位图表示**********/ int dy = (binaryImageData->width % NATIVE_MACHINE_WORD == 0) ? binaryImageData->width / NATIVE_MACHINE_WORD : binaryImageData->width / NATIVE_MACHINE_WORD + 1; //图像每行像素用dy个机器字表示 int map_size = dy * binaryImageData->height; //图像总机器字数 potrace_word one_pixel_to_bit; //每个像素用0,1表示(0表示背景,1表示前景) int i,j; potrace_bitmap_t bit_img = {binaryImageData->width, binaryImageData->height, dy, (potrace_word*) malloc (map_size * sizeof(potrace_word))}; for(i=0; i<map_size; i++) { bit_img.map[i] = 0; for(j=0; j<32; j++) { one_pixel_to_bit = ((i%dy)*NATIVE_MACHINE_WORD+j) <= binaryImageData->widthStep ? (binaryImageData->imageData[i/dy*binaryImageData->widthStep+(i%dy)*NATIVE_MACHINE_WORD+j] != 0) : 0; bit_img.map[i] |= (one_pixel_to_bit<<(NATIVE_MACHINE_WORD-1-j)); } //printf("%x\n", bit_img.map[i]); } /**********将二值灰度图转换成位图表示**********/ potrace_param_t* potrace_param = potrace_param_default(); potrace_param->alphamax = 0.0; potrace_state_t* potrace_state = potrace_trace(potrace_param, &bit_img); potrace_param_free(potrace_param); free(bit_img.map); return potrace_state; }
int main() { int x, y, i; potrace_bitmap_t *bm; potrace_param_t *param; potrace_path_t *p; potrace_state_t *st; int n, *tag; potrace_dpoint_t(*c)[3]; /* create a bitmap */ bm = bm_new(WIDTH, HEIGHT); if (!bm) { fprintf(stderr, "Error allocating bitmap: %s\n", strerror(errno)); return 1; } /* fill the bitmap with some pattern */ for (y = 0; y < HEIGHT; y++) { for (x = 0; x < WIDTH; x++) { BM_PUT(bm, x, y, ((x * x + y * y * y) % 10000 < 5000) ? 1 : 0); } } /* set tracing parameters, starting from defaults */ param = potrace_param_default(); if (!param) { fprintf(stderr, "Error allocating parameters: %s\n", strerror(errno)); return 1; } param->turdsize = 0; /* trace the bitmap */ st = potrace_trace(param, bm); if (!st || st->status != POTRACE_STATUS_OK) { fprintf(stderr, "Error tracing bitmap: %s\n", strerror(errno)); return 1; } bm_free(bm); /* output vector data, e.g. as a rudimentary EPS file */ printf("%%!PS-Adobe-3.0 EPSF-3.0\n"); printf("%%%%BoundingBox: 0 0 %d %d\n", WIDTH, HEIGHT); printf("gsave\n"); /* draw each curve */ p = st->plist; while (p != NULL) { n = p->curve.n; tag = p->curve.tag; c = p->curve.c; printf("%f %f moveto\n", c[n - 1][2].x, c[n - 1][2].y); for (i = 0; i < n; i++) { switch (tag[i]) { case POTRACE_CORNER: printf("%f %f lineto\n", c[i][1].x, c[i][1].y); printf("%f %f lineto\n", c[i][2].x, c[i][2].y); break; case POTRACE_CURVETO: printf("%f %f %f %f %f %f curveto\n", c[i][0].x, c[i][0].y, c[i][1].x, c[i][1].y, c[i][2].x, c[i][2].y); break; } } /* at the end of a group of a positive path and its negative children, fill. */ if (p->next == NULL || p->next->sign == '+') { printf("0 setgray fill\n"); } p = p->next; } printf("grestore\n"); printf("%%EOF\n"); potrace_state_free(st); potrace_param_free(param); return 0; }
static void dopts(int ac, char *av[]) { int c; char *p; int i, j, r; dim_t dim, dimx, dimy; int matches, bestmatch; /* defaults */ backend_lookup("eps", &info.backend); info.debug = 0; info.width_d.x = UNDEF; info.height_d.x = UNDEF; info.rx = UNDEF; info.ry = UNDEF; info.sx = UNDEF; info.sy = UNDEF; info.stretch = 1; info.lmar_d.x = UNDEF; info.rmar_d.x = UNDEF; info.tmar_d.x = UNDEF; info.bmar_d.x = UNDEF; info.angle = 0; info.paperwidth = DEFAULT_PAPERWIDTH; info.paperheight = DEFAULT_PAPERHEIGHT; info.tight = 0; info.unit = 10; info.compress = 1; info.pslevel = 2; info.color = 0x000000; info.gamma = 2.2; info.param = potrace_param_default(); if (!info.param) { fprintf(stderr, ""POTRACE": %s\n", strerror(errno)); exit(1); } info.longcoding = 0; info.outfile = NULL; info.blacklevel = 0.5; info.invert = 0; info.opaque = 0; info.grouping = 1; info.fillcolor = 0xffffff; info.progress = 0; info.progress_bar = DEFAULT_PROGRESS_BAR; while ((c = getopt_long(ac, av, shortopts, longopts, NULL)) != -1) { switch (c) { case 'h': fprintf(stdout, ""POTRACE" "VERSION". Transforms bitmaps into vector graphics.\n\n"); usage(stdout); exit(0); break; case 'v': case 'V': fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2015 Peter Selinger.\n"); fprintf(stdout, "Library version: %s\n", potrace_version()); show_defaults(stdout); exit(0); break; case 'l': fprintf(stdout, ""POTRACE" "VERSION". Copyright (C) 2001-2015 Peter Selinger.\n\n"); license(stdout); exit(0); break; case 'W': info.width_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case 'H': info.height_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case 'r': parse_dimensions(optarg, &p, &dimx, &dimy); if (*p == 0 && dimx.d == 0 && dimy.d == 0 && dimx.x != 0.0 && dimy.x != 0.0) { info.rx = dimx.x; info.ry = dimy.x; break; } dim = parse_dimension(optarg, &p); if (*p == 0 && dim.d == 0 && dim.x != 0.0) { info.rx = info.ry = dim.x; break; } fprintf(stderr, ""POTRACE": invalid resolution -- %s\n", optarg); exit(1); break; case 'x': parse_dimensions(optarg, &p, &dimx, &dimy); if (*p == 0 && dimx.d == 0 && dimy.d == 0) { info.sx = dimx.x; info.sy = dimy.x; break; } dim = parse_dimension(optarg, &p); if (*p == 0 && dim.d == 0) { info.sx = info.sy = dim.x; break; } fprintf(stderr, ""POTRACE": invalid scaling factor -- %s\n", optarg); exit(1); break; case 'S': info.stretch = atof(optarg); break; case 'M': info.lmar_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } info.rmar_d = info.tmar_d = info.bmar_d = info.lmar_d; break; case 'L': info.lmar_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case 'R': info.rmar_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case 'T': info.tmar_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case 'B': info.bmar_d = parse_dimension(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid dimension -- %s\n", optarg); exit(1); } break; case OPT_TIGHT: info.tight = 1; break; case 'A': info.angle = strtod(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid angle -- %s\n", optarg); exit(1); } break; case 'P': matches = 0; bestmatch = 0; for (i=0; pageformat[i].name!=NULL; i++) { if (strcasecmp(pageformat[i].name, optarg)==0) { matches = 1; bestmatch = i; break; } else if (strncasecmp(pageformat[i].name, optarg, strlen(optarg))==0) { /* don't allow partial match on "10x14" */ if (optarg[0] != '1') { matches++; bestmatch = i; } } } if (matches == 1) { info.paperwidth = pageformat[bestmatch].w; info.paperheight = pageformat[bestmatch].h; break; } parse_dimensions(optarg, &p, &dimx, &dimy); if (*p == 0) { info.paperwidth = (int)rint(double_of_dim(dimx, DEFAULT_DIM)); info.paperheight = (int)rint(double_of_dim(dimy, DEFAULT_DIM)); break; } if (matches == 0) { fprintf(stderr, ""POTRACE": unrecognized page format -- %s\n", optarg); } else { fprintf(stderr, ""POTRACE": ambiguous page format -- %s\n", optarg); } j = fprintf(stderr, "Use one of: "); for (i=0; pageformat[i].name!=NULL; i++) { if (j + strlen(pageformat[i].name) > 75) { fprintf(stderr, "\n"); j = 0; } j += fprintf(stderr, "%s, ", pageformat[i].name); } fprintf(stderr, "or specify <dim>x<dim>.\n"); exit(1); break; case 't': info.param->turdsize = atoi(optarg); break; case 'u': info.unit = strtod(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid unit -- %s\n", optarg); exit(1); } break; case 'c': info.pslevel = 2; info.compress = 0; break; case '2': info.pslevel = 2; info.compress = 1; break; case '3': #ifdef HAVE_ZLIB info.pslevel = 3; info.compress = 1; #else fprintf(stderr, ""POTRACE": option -3 not supported, using -2 instead.\n"); fflush(stderr); info.pslevel = 2; info.compress = 1; #endif break; case 'e': backend_lookup("eps", &info.backend); break; case 'p': backend_lookup("postscript", &info.backend); break; case 's': backend_lookup("svg", &info.backend); break; case 'g': backend_lookup("pgm", &info.backend); break; case 'b': r = backend_lookup(optarg, &info.backend); if (r==1 || r==2) { if (r==1) { fprintf(stderr, ""POTRACE": unrecognized backend -- %s\n", optarg); } else { fprintf(stderr, ""POTRACE": ambiguous backend -- %s\n", optarg); } j = fprintf(stderr, "Use one of: "); backend_list(stderr, j, 70); fprintf(stderr, ".\n"); exit(1); } break; case 'd': info.debug = atoi(optarg); break; case 'C': info.color = parse_color(optarg); if (info.color == -1) { fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg); exit(1); } break; case OPT_FILLCOLOR: info.fillcolor = parse_color(optarg); if (info.fillcolor == -1) { fprintf(stderr, ""POTRACE": invalid color -- %s\n", optarg); exit(1); } info.opaque = 1; break; case 'z': matches = 0; bestmatch = 0; for (i=0; turnpolicy[i].name!=NULL; i++) { if (strcasecmp(turnpolicy[i].name, optarg)==0) { matches = 1; bestmatch = i; break; } else if (strncasecmp(turnpolicy[i].name, optarg, strlen(optarg))==0) { matches++; bestmatch = i; } } if (matches == 1) { info.param->turnpolicy = turnpolicy[bestmatch].n; break; } if (matches == 0) { fprintf(stderr, ""POTRACE": unrecognized turnpolicy -- %s\n", optarg); } else { fprintf(stderr, ""POTRACE": ambiguous turnpolicy -- %s\n", optarg); } j = fprintf(stderr, "Use one of: "); for (i=0; turnpolicy[i].name!=NULL; i++) { if (j + strlen(turnpolicy[i].name) > 75) { fprintf(stderr, "\n"); j = 0; } j += fprintf(stderr, "%s%s", turnpolicy[i].name, turnpolicy[i+1].name ? ", " : ""); } fprintf(stderr, ".\n"); exit(1); break; case 'G': info.gamma = atof(optarg); break; case 'n': info.param->opticurve = 0; break; case 'q': info.longcoding = 1; break; case 'a': info.param->alphamax = strtod(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid alphamax -- %s\n", optarg); exit(1); } break; case 'O': info.param->opttolerance = strtod(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid opttolerance -- %s\n", optarg); exit(1); } break; case 'o': free(info.outfile); info.outfile = strdup(optarg); if (!info.outfile) { fprintf(stderr, ""POTRACE": %s\n", strerror(errno)); exit(2); } break; case 'k': info.blacklevel = strtod(optarg, &p); if (*p) { fprintf(stderr, ""POTRACE": invalid blacklevel -- %s\n", optarg); exit(1); } break; case 'i': info.invert = 1; break; case OPT_OPAQUE: info.opaque = 1; break; case OPT_GROUP: info.grouping = 2; break; case OPT_FLAT: info.grouping = 0; break; case OPT_PROGRESS: info.progress = 1; break; case OPT_TTY: if (strcmp(optarg, "dumb") == 0) { info.progress_bar = progress_bar_simplified; } else if (strcmp(optarg, "vt100") == 0) { info.progress_bar = progress_bar_vt100; } else { fprintf(stderr, ""POTRACE": invalid tty mode -- %s. Try --help for more info\n", optarg); exit(1); } break; case '?': fprintf(stderr, "Try --help for more info\n"); exit(1); break; default: fprintf(stderr, ""POTRACE": Unimplemented option -- %c\n", c); exit(1); } } info.infiles = &av[optind]; info.infilecount = ac-optind; info.some_infiles = info.infilecount ? 1 : 0; /* if "--" was used, even an empty list of filenames is considered "some" filenames. */ if (strcmp(av[optind-1], "--") == 0) { info.some_infiles = 1; } }
int main(int argc, char **argv) { const std::string sourceInput = argv[1]; cv::VideoCapture sourceCapture(atoi(sourceInput.c_str())); // cv::VideoCapture sourceCapture(sourceInput); if (!sourceCapture.isOpened()) { LOG_ERROR("can't open %s", sourceInput.c_str()); return -1; } cv::namedWindow(WIN_MAIN); cv::namedWindow(WIN_ANALYZE); cv::namedWindow(WIN_DEBUG); cv::Mat img_source, img_gray, img_bw, img_edges, img_gray_blur; printf("using potrace: %s\n", potrace_version()); while (sourceCapture.isOpened()) //Show the image captured in the window and repeat { sourceCapture.read(img_source); cvtColor(img_source, img_gray, CV_BGR2GRAY); uchar med = 0; assert(median(img_gray, med)); cv::threshold(img_gray, img_bw, med, 255, cv::THRESH_BINARY); potrace_bitmap_t* bm = create_bm_from_Mat(img_bw); assert(bm != nullptr); potrace_param_t* param = potrace_param_default(); potrace_state_t *state = potrace_trace(param, bm); assert(state->status == POTRACE_STATUS_OK); potrace_path_t* path = state->plist; std::vector<std::vector<cv::Point> > contours; contours.empty(); while (path != nullptr) { std::vector<cv::Point> contour; for (int i = 0; i < path->curve.n; ++i) { path->curve.tag[i]; contour.push_back(cv::Point(path->curve.c[i][2].x, path->curve.c[i][2].y)); } contours.push_back(contour); path = path->next; } printf("%d\n", contours.size()); cv::drawContours(img_source, contours, -1, cv::Scalar(0, 0, 0), 2); potrace_state_free(state); release_bm(bm); potrace_param_free(param); /// Convert the image to grayscale cv::imshow(WIN_MAIN, img_source); cv::imshow(WIN_DEBUG, img_bw); char c = cv::waitKey(33); if (c == 27) { cv::imwrite("/tmp/lastframe.jpg", img_source); break; } } cv::destroyWindow(WIN_MAIN); cv::destroyWindow(WIN_ANALYZE); cv::destroyWindow(WIN_DEBUG); return 0; }
JNIEXPORT jobject JNICALL Java_com_jiangpeng_android_antrace_Utils_traceImage(JNIEnv* env, jobject thiz, jobject bitmap) { AndroidBitmapInfo info; int ret = 0; void* src_pixels = 0; if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { return NULL; } if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { return NULL; } if ((ret = AndroidBitmap_lockPixels(env, bitmap, &src_pixels)) < 0) { return NULL; } potrace_param_t* param_t = potrace_param_default(); param_t->turdsize = 15; param_t->opttolerance = 0.8; potrace_bitmap_t* bmp_t = bm_new(info.width, info.height); //memcpy(bmp_t->map, src_pixels, bmp_t->dy * bmp_t->h * BM_WORDSIZE); const int kShiftBits = 20; const int32_t kRedRatio = static_cast<int32_t>((1 << kShiftBits) * 0.21f); const int32_t kGreenRatio = static_cast<int32_t>((1 << kShiftBits) * 0.71f); const int32_t kBlueRatio = static_cast<int32_t>((1 << kShiftBits) * 0.07f); for (uint32_t scan_line = 0; scan_line < info.height; scan_line++) { pixel32_t* src = reinterpret_cast<pixel32_t*>(src_pixels); pixel32_t* src_line_end = src + info.width; int x = 0; while (src < src_line_end) { int32_t src_red = src->rgba8[0]; int32_t src_green = src->rgba8[1]; int32_t src_blue = src->rgba8[2]; int32_t src_alpha = src->rgba8[3]; int32_t dst_color = (kRedRatio * src_red + kGreenRatio * src_green + kBlueRatio * src_blue) >> kShiftBits; if (dst_color > 128) { BM_PUT(bmp_t, x, info.height - 1 - scan_line, 1); } else { BM_PUT(bmp_t, x, info.height - 1 - scan_line, 0); } src++; ++x; } src_pixels = reinterpret_cast<char*>(src_pixels) + info.stride; } if(s_state != NULL) { potrace_state_free(s_state); s_state = NULL; } s_state = potrace_trace(param_t, bmp_t); potrace_param_free(param_t); bm_free(bmp_t); AndroidBitmap_unlockPixels(env, bitmap); if (!s_state || s_state->status != POTRACE_STATUS_OK) { return NULL; } potrace_path_t* start = s_state->plist; jobject prev = 0; jclass cls = env->FindClass("com/jiangpeng/android/antrace/Objects/path"); jobject retPath = 0; for(potrace_path_t* n = start; n != 0; n = n->next) { jobject path = createPath(env, n); if(retPath == 0) { retPath = path; } if(prev != 0) { jfieldID fid = env->GetFieldID(cls, "next", "Lcom/jiangpeng/android/antrace/Objects/path;"); env->SetObjectField(prev, fid, path); env->DeleteLocalRef(prev); } prev = path; } env->DeleteLocalRef(cls); return retPath; }
int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, OUTPUT_FMT_ID aFormat, int aDpi_X, int aDpi_Y, BMP2CMP_MOD_LAYER aModLayer ) { potrace_param_t* param; potrace_state_t* st; // set tracing parameters, starting from defaults param = potrace_param_default(); if( !param ) { fprintf( stderr, "Error allocating parameters: %s\n", strerror( errno ) ); return 1; } param->turdsize = 0; /* convert the bitmap to curves */ st = potrace_trace( param, aPotrace_bitmap ); if( !st || st->status != POTRACE_STATUS_OK ) { if( st ) { potrace_state_free( st ); } potrace_param_free( param ); fprintf( stderr, "Error tracing bitmap: %s\n", strerror( errno ) ); return 1; } BITMAPCONV_INFO info; info.m_PixmapWidth = aPotrace_bitmap->w; info.m_PixmapHeight = aPotrace_bitmap->h; // the bitmap size in pixels info.m_Paths = st->plist; info.m_Outfile = aOutfile; switch( aFormat ) { case KICAD_LOGO: info.m_Format = KICAD_LOGO; info.m_ScaleX = 1e3 * 25.4 / aDpi_X; // the conversion scale from PPI to micro info.m_ScaleY = 1e3 * 25.4 / aDpi_Y; // Y axis is top to bottom info.CreateOutputFile(); break; case POSTSCRIPT_FMT: info.m_Format = POSTSCRIPT_FMT; info.m_ScaleX = 1.0; // the conversion scale info.m_ScaleY = info.m_ScaleX; // output vector data, e.g. as a rudimentary EPS file (mainly for tests) info.CreateOutputFile(); break; case EESCHEMA_FMT: info.m_Format = EESCHEMA_FMT; info.m_ScaleX = 1000.0 / aDpi_X; // the conversion scale from PPI to UI info.m_ScaleY = -1000.0 / aDpi_Y; // Y axis is bottom to Top for components in libs info.CreateOutputFile(); break; case PCBNEW_KICAD_MOD: info.m_Format = PCBNEW_KICAD_MOD; info.m_ScaleX = 1e6 * 25.4 / aDpi_X; // the conversion scale from PPI to UI info.m_ScaleY = 1e6 * 25.4 / aDpi_Y; // Y axis is top to bottom in modedit info.CreateOutputFile( aModLayer ); break; default: break; } bm_free( aPotrace_bitmap ); potrace_state_free( st ); potrace_param_free( param ); return 0; }