/*----------------------------------------------------------------------- */ SEXP lib_erode_dilate (SEXP x, SEXP kernel, SEXP what, SEXP binary) { numeric resetTo, * tgt, * src, *kern, min, max; int nz, i, j, nprotect; int * dim; PointXY size, ksize, pt; SEXP res; validImage(x,0); validImage(kernel,0); /* value to reset the checked part t */ if ( INTEGER(what)[0] == DILATE ) resetTo = 1.0; /* checking background, reseting to 1 */ else resetTo = 0.0; /* checking foreground, reseting to 0 */ dim = INTEGER ( GET_DIM(x) ); size.x = dim[0]; size.y = dim[1]; nz = getNumberOfFrames(x,0); kern = REAL (kernel); ksize.x = INTEGER ( GET_DIM(kernel) )[0]; ksize.y = INTEGER ( GET_DIM(kernel) )[1]; nprotect = 0; PROTECT ( res = Rf_duplicate(x) ); nprotect++; for ( i = 0; i < nz; i++ ) { tgt = &( REAL(res)[i * size.x * size.y] ); src = &( REAL(x)[i * size.x * size.y] ); if ( ! INTEGER(binary)[0] ) { min = max = src[0]; for ( j = 0; j < size.x * size.y; j++ ) { if (src[j] > max) max = src[j]; if (src[j] < min) min = src[j]; } for ( j = 0; j < size.x * size.y; j++ ) { pt = pointFromIndex (j, size.x); tgt[j] = _greymatch(kern, &ksize, src, &size, &pt, INTEGER(what)[0], min , max); } } else { for ( j = 0; j < size.x * size.y; j++ ) { if ( tgt[j] == resetTo ) continue; pt = pointFromIndex (j, size.x); if ( !_match(kern, &ksize, src, &size, &pt, resetTo) ) tgt[j] = resetTo; } } } UNPROTECT (nprotect); return res; }
static void TestBitmapSerialization(const SkBitmap& validBitmap, const SkBitmap& invalidBitmap, bool shouldSucceed, skiatest::Reporter* reporter) { sk_sp<SkImage> validImage(SkImage::MakeFromBitmap(validBitmap)); sk_sp<SkImageFilter> validBitmapSource(SkImageSource::Make(std::move(validImage))); sk_sp<SkImage> invalidImage(SkImage::MakeFromBitmap(invalidBitmap)); sk_sp<SkImageFilter> invalidBitmapSource(SkImageSource::Make(std::move(invalidImage))); sk_sp<SkImageFilter> xfermodeImageFilter( SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, std::move(invalidBitmapSource), std::move(validBitmapSource), nullptr)); sk_sp<SkImageFilter> deserializedFilter( TestFlattenableSerialization<SkImageFilter>( xfermodeImageFilter.get(), shouldSucceed, reporter)); // Try to render a small bitmap using the invalid deserialized filter // to make sure we don't crash while trying to render it if (shouldSucceed) { SkBitmap bitmap; bitmap.allocN32Pixels(24, 24); SkCanvas canvas(bitmap); canvas.clear(0x00000000); SkPaint paint; paint.setImageFilter(deserializedFilter); canvas.clipRect(SkRect::MakeXYWH(0, 0, SkIntToScalar(24), SkIntToScalar(24))); canvas.drawBitmap(bitmap, 0, 0, &paint); } }
/* -------------------------------------------------------------------------- */ SEXP fillHull(SEXP x) { SEXP res; int nprotect = 0; int nz; // check image validity validImage(x,0); nz = getNumberOfFrames(x, 0); int *dim=INTEGER(GET_DIM(x)); XYPoint size(dim[0], dim[1]); // return itself if nothing to do if (size.x <= 0 || size.y <= 0 || nz < 1) return x; // do fillHull PROTECT(res = Rf_duplicate(x)); nprotect++; if (IS_INTEGER(res)) { for (int i=0; i < nz; i++) _fillHullT<int>(&(INTEGER(res)[i*size.x*size.y]), size); } else if (IS_NUMERIC(res)) { for (int i=0; i < nz; i++) _fillHullT<double>(&(REAL(res)[i*size.x*size.y]), size); } UNPROTECT (nprotect); return res; }
/* -------------------------------------------------------------------------- */ SEXP floodFill(SEXP x, SEXP point, SEXP col, SEXP tol) { int i, nz, *dim; int nprotect=0; XYPoint pt; SEXP res; // check image validity validImage(x,0); nz = getNumberOfFrames(x, 0); dim = INTEGER(GET_DIM(x)); XYPoint size(dim[0], dim[1]); if (size.x <= 0 || size.y <= 0) error("image must have positive dimensions"); if (LENGTH(point) != 2*nz) error("point must have a size of two times the number of frames"); if (LENGTH(col) != nz) error("color must have the same size as the number of frames"); // initialize result PROTECT(res = Rf_duplicate(x)); nprotect++; // do the job over images for (i=0; i<nz; i++) { pt.x = INTEGER(point)[i]-1; pt.y = INTEGER(point)[nz+i]-1; if (IS_NUMERIC(res)) _floodFill<double>(&(REAL(res)[i*size.x*size.y]), size, pt, REAL(col)[i], REAL(tol)[0]); if (IS_INTEGER(res)) _floodFill<int>(&(INTEGER(res)[i*size.x*size.y]), size, pt, INTEGER(col)[i], REAL(tol)[0]); } UNPROTECT (nprotect); return res; }
SEXP lib_display(SEXP x, SEXP caption, SEXP useGTK) { #ifndef WIN32 pthread_t res; #endif validImage(x,0); #ifdef USE_GTK if ( LOGICAL(useGTK)[0] ) { if ( GTK_OK ) _showInGtkWindow (x, caption); else error ( "GTK+ was not properly initialised" ); return R_NilValue; } #endif #ifdef WIN32 error ( "ImageMagick 'display' is not available on Windows" ); #else if ( THREAD_ON ) error ( "Cannot display multiple windows. Please close the currently displayed window first." ); if ( pthread_create(&res, NULL, _showInImageMagickWindow, (void *)x ) != 0 ) error ( "Failed to create 'display' thread" ); #endif return R_NilValue; }
/*----------------------------------------------------------------------- */ SEXP lib_writeImages (SEXP x, SEXP files, SEXP quality) { int nz, nfiles, i; Image * images, * image; ImageInfo *image_info; ExceptionInfo exception; /* basic checks */ validImage(x,0); images = sexp2Magick (x); nz = GetImageListLength(images); nfiles = LENGTH (files); if ( nfiles != 1 && nfiles != nz) error ( "number of files must be 1, or equal to the size of the image stack" ); if ( images == NULL || GetImageListLength (images) < 1 ) error ( "cannot write an empty image" ); GetExceptionInfo (&exception); image_info = CloneImageInfo ( (ImageInfo *)NULL ); /* set attributes in image_info*/ image_info->compression = images->compression; image_info->quality = (unsigned int) INTEGER (quality)[0]; if ( nfiles == 1 ) { /* save into a single file, TIFF, GIF, or automatically add file suffixes */ strcpy (image_info->filename, CHAR(STRING_ELT(files, 0)) ); /* we want to overwrite the feature imported from SEXP image */ strcpy (images->filename, image_info->filename); WriteImages(image_info, images, CHAR(STRING_ELT(files, 0)), &exception); CatchException (&exception); } else { /* save each frame into a separate file */ for ( i = 0; i < nz; i++ ) { image = GetImageFromList (images, i); if ( image == NULL || GetImageListLength (image) < 1 ) { warning ( "cannot write an empty image, skipping" ); continue; } strcpy (image_info->filename, CHAR(STRING_ELT(files, i))); /* we want to overwrite the feature imported from SEXP image */ strcpy (image->filename, image_info->filename); WriteImage (image_info, image); CatchException (&image->exception); // WriteImages(image_info, image, CHAR(STRING_ELT(files, i)), &exception); // CatchException (&exception); } } image_info = DestroyImageInfo (image_info); images = DestroyImageList (images); DestroyExceptionInfo(&exception); return R_NilValue; }
// Compute Euclidean (L2)/Manhattan (L1) distance map of matrix _a // Input: numeric matrix _a, of size width*height, where 0 is background and everything else is foreground. _a shouldn't contain any NAs // Input: integer _metric. If 0, will compute Euclidean distance and Manhattan distance otherwise // Output: distance matrix of same size as _a SEXP distmap(SEXP _a, SEXP _metric) { SEXP res; int i,nprotect=0,nz; // check validity validImage(_a,0); // initialize width, height, dim width=INTEGER(GET_DIM(_a))[0]; height=INTEGER(GET_DIM(_a))[1]; nz=getNumberOfFrames(_a,0); // initialize vj, where (i,vj[i]) are the coordinates of the closest background pixel to a(i,j) with vj[i]>=j vj=(int *)R_Calloc(height,int); // initialize d, the output distance matrix PROTECT(res = allocVector(REALSXP, XLENGTH(_a)) ); nprotect++; DUPLICATE_ATTRIB(res, _a); d=REAL(res); for (i=0;i<height*width*nz;i++) d[i]=R_PosInf; // initialize dist, the distance type metric=INTEGER(_metric)[0]; // do the job int sizexy = height*width; int offset = 0; for (i=0; i<nz; i++, offset+=sizexy) { d = &(REAL(res)[offset]); switch (TYPEOF(_a)) { case LGLSXP: case INTSXP: _distmap<int>( &(INTEGER(_a)[offset]) ); break; case REALSXP: _distmap<double>( &(REAL(_a)[offset]) ); break; } } // final square root for Euclidean distance d=REAL(res); if (metric==0) for (i=0;i<height*width*nz;i++) d[i]=sqrt(d[i]); R_Free(vj); UNPROTECT (nprotect); return res; }
SEXP affine(SEXP _a, SEXP _b, SEXP _m, SEXP _filter) { int width, height, nz; int owidth, oheight; int filter; double *a, *m, *b; // check image validity validImage(_a, 0); // initialize width, height, nz width = INTEGER(GET_DIM(_a))[0]; height = INTEGER(GET_DIM(_a))[1]; nz = getNumberOfFrames(_a, 0); // initialize a, m, filter a = REAL(_a); m = REAL(_m); filter = INTEGER(_filter)[0]; // get output image b data owidth = INTEGER(GET_DIM(_b))[0]; oheight = INTEGER(GET_DIM(_b))[1]; b = REAL(_b); // apply transform for (int z=0; z<nz; z++) { for (int y=0; y<oheight; y++) { for (int x=0; x<owidth; x++) { int idx = x + y*owidth + z*owidth*oheight; double bg = b[idx]; double tx = m[0]*x + m[1]*y + m[2]; double ty = m[3]*x + m[4]*y + m[5]; int ftx = floor(tx); int fty = floor(ty); double dx = tx-ftx; double dy = ty-fty; double pa = peekpixel(ftx, fty, z, width, height, a, bg); // bilinear filter? if (filter==1) { double pb = peekpixel(ftx+1, fty, z, width, height, a, bg); double pc = peekpixel(ftx, fty+1, z, width, height, a, bg); double pd = peekpixel(ftx+1, fty+1, z, width, height, a, bg); pa = (1-dy)*(pa*(1-dx) + pb*dx) + dy*(pc*(1-dx) + pd*dx); } b[idx] = pa; } } } return _b; }
/* -------------------------------------------------------------------------- */ SEXP bwlabel(SEXP x) { int i, kx, ky, nz, *dim; int nprotect=0; double index; XYPoint pt; SEXP res; // check image validity validImage(x,0); nz = getNumberOfFrames(x, 0); dim = INTEGER(GET_DIM(x)); XYPoint size(dim[0], dim[1]); if (size.x <= 0 || size.y <= 0) error("image must have positive dimensions"); // initialize result PROTECT(res = Rf_duplicate(x)); nprotect++; // assuming binary images: 0 is background and everything else foreground // foreground is converted here to -1.0 // NO NO NO: I've splitted some labelled objects, I want to relabel the parts, // so I put them to -REAL(res)[i] instead of -1, otherwise they will be merged // as they are connected for (i=0; i<nz*size.x*size.y; i++) { if (REAL(res)[i]!=0.0) REAL(res)[i]=-REAL(res)[i]; } // do the job over images // every pixel equals with R_PosInf is filled with an increasing index, starting from 1 for (i=0; i<nz; i++) { index = 1.0; for (ky=0; ky<size.y ; ky++) { for (kx=0; kx<size.x ; kx++) { if ( REAL(res)[kx + ky*size.x + i*size.x*size.y] < 0 ) { pt.x = kx; pt.y = ky; _floodFill<double>(&(REAL(res)[i*size.x*size.y]), size, pt, index, 0.0); index = index + 1.0; } } } } UNPROTECT (nprotect); return res; }
SEXP lib_animate (SEXP x) { #ifndef WIN32 pthread_t res; #endif validImage(x,0); #ifdef WIN32 error ( "ImageMagick 'animate' is not available on Windows." ); #else if ( THREAD_ON ) error ( "Cannot display multiple windows. Please close the currently displayed window first." ); if ( pthread_create(&res, NULL, _animateInImageMagickWindow, (void *)x ) != 0 ) error ( "Failed to create 'animate' thread" ); #endif return R_NilValue; }
// Compute Euclidean (L2)/Manhattan (L1) distance map of matrix _a // Input: numeric matrix _a, of size width*height, where 0 is background and everything else is foreground. _a shouldn't contain any NAs // Input: integer _metric. If 0, will compute Euclidean distance and Manhattan distance otherwise // Output: distance matrix of same size as _a SEXP distmap(SEXP _a, SEXP _metric) { SEXP res; int i,nprotect=0,nz; // check validity validImage(_a,0); // initialize width, height, dim width=INTEGER(GET_DIM(_a))[0]; height=INTEGER(GET_DIM(_a))[1]; nz=getNumberOfFrames(_a,0); // initialize vj, where (i,vj[i]) are the coordinates of the closest background pixel to a(i,j) with vj[i]>=j vj=(int *)R_Calloc(height,int); // initialize a a=REAL(_a); // initialize d, the output distance matrix PROTECT(res=Rf_duplicate(_a)); nprotect++; d=REAL(res); for (i=0;i<height*width*nz;i++) d[i]=R_PosInf; // initialize dist, the distance type metric=INTEGER(_metric)[0]; // do the job for (i=0;i<nz;i++) { distmap_onesided(1); distmap_onesided(0); a=a+height*width; d=d+height*width; } // final square root for Euclidean distance d=REAL(res); if (metric==0) for (i=0;i<height*width*nz;i++) d[i]=sqrt(d[i]); // free vj R_Free(vj); UNPROTECT (nprotect); return res; }
uint8_t processPacket() { #endif uint8_t buffer[TFTP_PACKET_MAX_SIZE]; uint16_t readPointer; uint16_t writeAddr; // Transfer entire packet to RAM uint8_t *bufPtr = buffer; uint16_t count; #ifdef _DEBUG_TFTP traceln("Tftp: ----"); traceln("Tftp: Starting processing packet of size "); tracenum(packetSize); if(packetSize >= 0x800) traceln("Tftp: Overflow"); // step(); #endif readPointer = netReadWord(REG_S3_RX_RD0); #ifdef _DEBUG_TFTP traceln("Tftp: readPointer at position "); tracenum(readPointer); #endif if(readPointer == 0) readPointer += S3_RX_START; for(count = TFTP_PACKET_MAX_SIZE; count--;) { #ifdef _DEBUG_TFTP if((count == TFTP_PACKET_MAX_SIZE - 1) || (count == 0)) { traceln("Tftp: Reading from position "); tracenum(readPointer); } #endif *bufPtr++ = netReadReg(readPointer++); if(readPointer == S3_RX_END) readPointer = S3_RX_START; } netWriteWord(REG_S3_RX_RD0, readPointer); // Write back new pointer netWriteReg(REG_S3_CR, CR_RECV); while(netReadReg(REG_S3_CR)); #ifdef _DEBUG_TFTP traceln("Tftp: Bytes left to read "); tracenum(netReadWord(REG_S3_RX_RSR0)); #endif #ifdef _DEBUGMORE_TFTP // Dump packet bufPtr = buffer; traceln(""); for(count = TFTP_PACKET_MAX_SIZE / 2; count--;) { uint16_t val = *bufPtr++; val |= (*bufPtr++) << 8; tracenum(val); if((count % 8) == 0 && count != 0) traceln(""); else trace(" "); } #endif #ifdef _DEBUG_TFTP traceln("Tftp: Setting return address"); #endif // Set up return IP address and port uint8_t i; for(i = 0; i < 6; i++) netWriteReg(REG_S3_DIPR0 + i, buffer[i]); // Parse packet uint16_t tftpDataLen = (buffer[6] << 8) + buffer[7]; uint16_t tftpOpcode = (buffer[8] << 8) + buffer[9]; uint16_t tftpBlock = (buffer[10] << 8) + buffer[11]; #ifdef _DEBUG traceln("Tftp: This is block "); tracenum(tftpBlock); trace(" with opcode "); tracenum(tftpOpcode); trace(" and data length "); tracenum(tftpDataLen - (TFTP_OPCODE_SIZE + TFTP_BLOCKNO_SIZE)); #endif uint8_t returnCode = ERROR_UNKNOWN; uint16_t packetLength; switch(tftpOpcode) { case TFTP_OPCODE_RRQ: // Read request #ifdef _DEBUG_TFTP traceln("Tftp: Read request"); #endif break; case TFTP_OPCODE_WRQ: // Write request #ifdef _VERBOSE traceln("Tftp: Write request"); #endif // Flagging image as invalid since the flashing process has started eeprom_write_byte(EEPROM_IMG_STAT, EEPROM_IMG_BAD_VALUE); netWriteReg(REG_S3_CR, CR_RECV); netWriteReg(REG_S3_CR, CR_CLOSE); do { netWriteReg(REG_S3_MR, MR_UDP); netWriteReg(REG_S3_CR, CR_OPEN); #ifdef _TFTP_RANDOM_PORT netWriteWord(REG_S3_PORT0, (buffer[4]<<8) | ~buffer[5]); // Generate a 'random' TID (RFC1350) #else netWriteWord(REG_S3_PORT0, tftpPort); #endif if(netReadReg(REG_S3_SR) != SOCK_UDP) netWriteReg(REG_S3_CR, CR_CLOSE); } while(netReadReg(REG_S3_SR) != SOCK_UDP); #ifdef _DEBUG_TFTP traceln("Tftp: Changed to port "); #ifdef _TFTP_RANDOM_PORT tracenum((buffer[4]<<8) | (buffer[5]^0x55)); #else tracenum(tftpPort); #endif #endif lastPacket = 0; returnCode = ACK; // Send back acknowledge for packet 0 break; case TFTP_OPCODE_DATA: packetLength = tftpDataLen - (TFTP_OPCODE_SIZE + TFTP_BLOCKNO_SIZE); lastPacket = tftpBlock; writeAddr = (tftpBlock - 1) << 9; // Flash write address for this block #ifdef _VERBOSE traceln("Tftp: Data for block "); tracenum(lastPacket); #endif if((writeAddr + packetLength) > MAX_ADDR) { // Flash is full - abort with an error before a bootloader overwrite occurs // Application is now corrupt, so do not hand over. #ifdef _VERBOSE traceln("Tftp: Flash is full"); #endif returnCode = ERROR_FULL; } else { #ifdef _DEBUG_TFTP traceln("Tftp: Writing data from address "); tracenum(writeAddr); #endif uint8_t *pageBase = buffer + (UDP_HEADER_SIZE + TFTP_OPCODE_SIZE + TFTP_BLOCKNO_SIZE); // Start of block data uint16_t offset = 0; // Block offset // Round up packet length to a full flash sector size while(packetLength % SPM_PAGESIZE) packetLength++; #ifdef _DEBUG_TFTP traceln("Tftp: Packet length adjusted to "); tracenum(packetLength); #endif if(writeAddr == 0) { // First sector - validate if(!validImage(pageBase)) { returnCode = INVALID_IMAGE; /* FIXME: Validity checks. Small programms (under 512 bytes?) don't * have the the JMP sections and that is why app.bin was failing. * When flashing big binaries is fixed, uncomment the break below.*/ #ifndef _DEBUG_TFTP break; #endif } } // Flash packets for(offset = 0; offset < packetLength;) { uint16_t writeValue = (pageBase[offset]) | (pageBase[offset + 1] << 8); boot_page_fill(writeAddr + offset, writeValue); #ifdef _DEBUGMORE if((offset == 0) || ((offset == (packetLength - 2)))) { traceln("Tftp: Writing "); tracenum(writeValue); trace(" at offset "); tracenum(writeAddr + offset); } #endif offset += 2; if(offset % SPM_PAGESIZE == 0) { boot_page_erase(writeAddr + offset - SPM_PAGESIZE); boot_spm_busy_wait(); boot_page_write(writeAddr + offset - SPM_PAGESIZE); boot_spm_busy_wait(); boot_rww_enable(); } } if(packetLength < TFTP_DATA_SIZE) { // Flash is complete // Hand over to application #ifdef _VERBOSE traceln("Tftp: Flash is complete"); #endif // Flag the image as valid since we received the last packet eeprom_write_byte(EEPROM_IMG_STAT, EEPROM_IMG_OK_VALUE); returnCode = FINAL_ACK; } else { returnCode = ACK; } } break; // Acknowledgment case TFTP_OPCODE_ACK: #ifdef _DEBUG_TFTP traceln("Tftp: Acknowledge"); #endif break; // Error signal case TFTP_OPCODE_ERROR: #ifdef _DEBUG_TFTP traceln("Tftp: Error"); #endif break; default: #ifdef _DEBUG_TFTP traceln("Tftp: Invalid opcode "); tracenum(tftpOpcode); #endif // Invalid - return error returnCode = ERROR_INVALID; break; } return(returnCode); }
/*----------------------------------------------------------------------- */ SEXP thresh (SEXP x, SEXP param) { int dx, dy, nx, ny, nz, nprotect, * dim, xi, yi, u, v, i; int sx, ex, sy, ey; double offset, * tgt, * src, sum, mean, nFramePix; SEXP res; validImage(x,0); dim = INTEGER ( GET_DIM(x) ); nx = dim[0]; ny = dim[1]; nz = getNumberOfFrames(x,0); dx = (int)( REAL(param)[0] ); dy = (int)( REAL(param)[1] ); offset = REAL(param)[2]; nprotect = 0; nFramePix = (2 * dx + 1) * (2 * dy + 1); PROTECT ( res = Rf_duplicate(x) ); nprotect++; for ( i = 0; i < nz; i++ ) { tgt = &( REAL(res)[ i * nx * ny ] ); src = &( REAL(x)[ i * nx * ny ] ); for ( yi = dy; yi < ny - dy; yi++ ) { sum = 0.0; for ( xi = dx; xi < nx - dx; xi++ ) { if ( xi == dx) { /* first position in a row -- collect new sum */ for ( u = xi - dx; u <= xi + dx; u++ ) for ( v = yi - dy; v <= yi + dy; v++ ) sum += src [u + v * nx]; } else { /* frame moved in the row, modify sum */ for ( v = yi - dy; v <= yi + dy; v++ ) sum += src [xi + dx + v * nx] - src [ xi - dx - 1 + v * nx]; } /* calculate threshold and update tgt data */ mean = sum / nFramePix + offset; sx = xi; ex = xi; sy = yi; ey = yi; if ( xi == dx ) { /* left */ sx = 0; ex = dx; } else if ( xi == nx - dx - 1 ) { /* right */ sx = nx - dx - 1; ex = nx - 1; } if ( yi == dy ) { /* top */ sy = 0; ey = dy; } else if ( yi == ny - dy - 1 ) { /* bottom */ sy = ny - dy - 1; ey = ny - 1; } if ( ex - sx > 0 || ey - sy > 0 ) { for ( u = sx; u <= ex; u++ ) for ( v = sy; v <= ey; v++ ) tgt [u + v * nx] = ( src [u + v * nx] < mean ) ? BG : FG; } else /* thresh current pixel only */ tgt [xi + yi * nx] = ( src [xi + yi * nx] < mean ) ? BG : FG; } } } UNPROTECT (nprotect); return res; }