// Distorts anything that has a non-null pointer with the same pseudo-random // perspective distortion. Width and height only need to be set if there // is no pix. If there is a pix, then they will be taken from there. void GeneratePerspectiveDistortion(int width, int height, TRand* randomizer, Pix** pix, GenericVector<TBOX>* boxes) { if (pix != nullptr && *pix != nullptr) { width = pixGetWidth(*pix); height = pixGetHeight(*pix); } float* im_coeffs = nullptr; float* box_coeffs = nullptr; l_int32 incolor = ProjectiveCoeffs(width, height, randomizer, &im_coeffs, &box_coeffs); if (pix != nullptr && *pix != nullptr) { // Transform the image. Pix* transformed = pixProjective(*pix, im_coeffs, incolor); if (transformed == nullptr) { tprintf("Projective transformation failed!!\n"); return; } pixDestroy(pix); *pix = transformed; } if (boxes != nullptr) { // Transform the boxes. for (int b = 0; b < boxes->size(); ++b) { int x1, y1, x2, y2; const TBOX& box = (*boxes)[b]; projectiveXformSampledPt(box_coeffs, box.left(), height - box.top(), &x1, &y1); projectiveXformSampledPt(box_coeffs, box.right(), height - box.bottom(), &x2, &y2); TBOX new_box1(x1, height - y2, x2, height - y1); projectiveXformSampledPt(box_coeffs, box.left(), height - box.bottom(), &x1, &y1); projectiveXformSampledPt(box_coeffs, box.right(), height - box.top(), &x2, &y2); TBOX new_box2(x1, height - y1, x2, height - y2); (*boxes)[b] = new_box1.bounding_union(new_box2); } } free(im_coeffs); free(box_coeffs); }
/*! * pixProjectiveSampled() * * Input: pixs (all depths) * vc (vector of 8 coefficients for projective transformation) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary. * (2) Retains colormap, which you can do for a sampled transform.. * (3) For 8 or 32 bpp, much better quality is obtained by the * somewhat slower pixProjective(). See that function * for relative timings between sampled and interpolated. */ PIX * pixProjectiveSampled(PIX *pixs, l_float32 *vc, l_int32 incolor) { l_int32 i, j, w, h, d, x, y, wpls, wpld, color, cmapindex; l_uint32 val; l_uint32 *datas, *datad, *lines, *lined; PIX *pixd; PIXCMAP *cmap; PROCNAME("pixProjectiveSampled"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32) return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", procName, NULL); /* Init all dest pixels to color to be brought in from outside */ pixd = pixCreateTemplate(pixs); if ((cmap = pixGetColormap(pixs)) != NULL) { if (incolor == L_BRING_IN_WHITE) color = 1; else color = 0; pixcmapAddBlackOrWhite(cmap, color, &cmapindex); pixSetAllArbitrary(pixd, cmapindex); } else { if ((d == 1 && incolor == L_BRING_IN_WHITE) || (d > 1 && incolor == L_BRING_IN_BLACK)) pixClearAll(pixd); else pixSetAll(pixd); } /* Scan over the dest pixels */ datas = pixGetData(pixs); wpls = pixGetWpl(pixs); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); for (i = 0; i < h; i++) { lined = datad + i * wpld; for (j = 0; j < w; j++) { projectiveXformSampledPt(vc, j, i, &x, &y); if (x < 0 || y < 0 || x >=w || y >= h) continue; lines = datas + y * wpls; if (d == 1) { val = GET_DATA_BIT(lines, x); SET_DATA_BIT_VAL(lined, j, val); } else if (d == 8) { val = GET_DATA_BYTE(lines, x); SET_DATA_BYTE(lined, j, val); } else if (d == 32) { lined[j] = lines[x]; } else if (d == 2) { val = GET_DATA_DIBIT(lines, x); SET_DATA_DIBIT(lined, j, val); } else if (d == 4) { val = GET_DATA_QBIT(lines, x); SET_DATA_QBIT(lined, j, val); } } } return pixd; }