;+--------------------------------------------------------------------------- ; NAME: ; anim2cine ; ; PURPOSE: ; Create an mpeg or avi movie from two .cin files from Phantom 7 Cameras. ; The data can be color or monochrome ; ; CATEGORY: ; animation ; ; CALLING SEQUENCE: ; anim2cine, CineFile1, CineFile2, outFile=outfile, t1=t1, t2=t2 ; or ; ; INPUTS: ; CineFile1 - cine file ; CineFile2 - ; - ; OPTIONAL KEYWORD PARAMETERS: ; outFile - name of output MPEG file (will default to a nice name), or ; prefix - what would precede _shot_t1_t2 (in msec) in the output filename ; t1 - start time of animation in seconds ; t2 - end time of animation in seconds ; VIEW - if set, just displays images, and does not make an mpeg ; ndups - if given means repeat every image 'ndups' times ; despeckle - if set call despeckle routine (slow, but less "intrusive" ; than median) ; nSmooth - number input to median smoothing routine ; topPixels - ; botPixels - ; charsize - character size for plots. Default=2 ; ctb - color table for non-color image ; label1 - label on plot for CineFile1 (default='Monochrome') ; label2 - label on plot for CineFile2 (default='Color') ; verbose - if set will print out info as it works ; OUTPUTS: ; an MPEG file named by outFile keyword ; ; PROCEDURE: ; will assume Phantom 7 camera is the fastest ; EXAMPLE: ; ; anim2cine, '/p/nstxusr2/nstxphantom7/NSTX_130389.cin', $ ; '/p/nstxusr2/miro/MIRO_130389.cin', $ ; t1=0.02, t2=1.5, /verbose , /debug ; ; anim2cine, '/p/nstxusr2/nstxphantom7/NSTX_130387.cin', $ ; '/p/nstxusr2/miro/MIRO_130387.cin', $ ; t1=0.02, t2=1.4, /verbose ; ; anim2cine, shot=130370, t1=0.05, t2=0.58, /verbose, /view , /debug ; ; anim2cine, '/p/nstxusr2/nstxphantom7/NSTX_130388.cin', $ ; '/p/nstxusr2/phantom4/NSTX_130388.cin', $ ; t1=0, t2=2, ctb=0, /verbose , /debug ; ; anim2cine, shot=130375, /nonGlobal, $ ; t1=0, t2=2, ctb=0, /verbose , /debug ; ; mv files to /w/nstx.pppl.gov/htdocs/nstx/Software/Diagnostics/Miro for web viewing at ; http://nstx.pppl.gov/nstx/Software/Diagnostics/Miro/ ; ; MODIFICATION HISTORY: ; 12-Nov-2008 mods because cineload now assuming frame 0 is beginning of data ; 16-Jul-2008 Use Z-buffer, even when viewing, for smoother displays ; 15-Jul-2008 Written by Bill Davis ;------------------------------------------------------------------------------ PRO anim2cine, file1_in, file2_in, shot=shot, nonGlobal=nonGlobal, $ outDir=outDir, outFile=outfile, prefix=prefix, $ ; specify only one of these magnify=magnify, ctb=ctb, dialog=dialog, $$ ndups=ndups, skip=skip, border=border, $ topPixels=topPixels, botPixels=botPixels, $ debug=debug, nsmooth=nsmooth, mag1=mag1, mag2=mag2, $ thick=thick, badValue=badValue, framenum=framenum, $ inc=inc, t1_in=t1_in, t2_in=t2_in, type=type, $ label1=label1, label2=label2, charsize=charsize, $ gamma1=gamma1, gamma2=gamma2, $ VIEW=view, xsize=xsize, ysize=ysize, verbose=verbose ; determine if monitor is 24-bit color (pixmap always?) set_plot,'x' Device, Get_Visual_Depth=thisDepth IF thisDepth GT 8 THEN BEGIN Device, Decomposed=0 truecolor = 1 ENDIF ELSE truecolor = 0 if not trueColor then begin if dialog then a=dialog_message('This may only runs on 24-bit monitors') ;;; return endif if n_elements(t1_in) eq 0 then t1_in = 0. ; sec ;;;if n_elements(t2_in) eq 0 then t2_in = t1_in + 0.1 if n_elements( ndups ) eq 0 then ndups=0 ; for output frames if n_elements( debug ) eq 0 then debug=0 if n_elements( verbose ) eq 0 then verbose=0 if n_elements( dialog ) eq 0 then dialog = 1 if n_elements( nonGlobal ) eq 0 then nonGlobal=0 if n_elements( nsmooth ) eq 0 then nsmooth=0 if n_elements( mag1 ) eq 0 then mag1=1 if n_elements( mag2 ) eq 0 then mag2=1 if n_elements( skip) gt 0 then inc=skip+1 ; alternate input for inc if n_elements( inc) eq 0 then inc=1 ; 2 will skip every other frame if n_elements( border ) eq 0 then border=10 if n_elements( topPixels ) eq 0 then topPixels= 20 if n_elements( botPixels ) eq 0 then botPixels= 30 if n_elements( prefix ) eq 0 then prefix = 'NSTXcines_' else begin if lastChar( prefix ) ne '_' then prefix= prefix + '_' endelse if n_elements( type ) eq 0 then type = 'mpg' if n_elements( charsize ) eq 0 then charsize = 1.5 if n_elements( outDir ) eq 0 then outDir = '' if debug then view = 1 if n_elements( view ) eq 0 then view = 0 if n_elements( file1_in ) eq 0 then begin if n_elements( shot ) ne 0 then begin file1_in= file_search( '/p/nstxusr2/nstxphantom7/*'+strtrim(shot,2)+'.cin*') endif if nwords( file1_in ) eq 0 then begin file1_in= file_search( '/p/nstxusr2/phantom4/*'+strtrim(shot,2)+'.cin*') endif if nwords( file1_in ) eq 0 then begin file1_in = DIALOG_PICKFILE( title='Choose a .cin file', filter='*.cin*', $ path='/p/nstxusr2/nstxphantom7/') if file1_in eq '' then return endif endif file1 = file1_in[0] if strpos(file1,'.gz') eq strlen(file1)-3 then begin print, ' >>> (Unzipping file '+file1+'-- have patience!)' spawn, 'gunzip '+file1, result, Exit_Status=errors if errors then print,"*** probably don't have privileges to unzip file" file1 = strpos( file1, 0, strlen(file1)-3 ) endif if n_elements( file2_in ) eq 0 then begin dir2 = '/p/nstxusr2/miro/' if nonGlobal then dir2 = '/p/nstxusr2/phantom4/' fdecomp, file1, disk, dir1, name, ext if dir1 eq dir2 then dir2 = '/p/nstxusr2/nstxphantom7/' if n_elements( shot ) ne 0 then begin file2_in= file_search( dir2+'*'+strtrim(shot,2)+'.cin*') endif if nwords( file2_in ) eq 0 then begin file2_in = DIALOG_PICKFILE( title='Choose a .cin file', filter='*.cin*', $ path=dir2) if file2_in eq '' then return endif endif file2 = file2_in[0] if strpos(file2,'.gz') eq strlen(file2)-3 then begin print, ' >>> (Unzipping file '+file2+'-- have patience!)' spawn, 'gunzip '+file2, result, Exit_Status=errors if errors then print,"*** probably don't have privileges to unzip file" file2= file_search( '/p/nstxusr2/miro/*'+strtrim(shot,2)+'.cin*') endif if isnumber( file1 ) or isnumber( file2 ) then begin print, 'One of the file specifications is a number!' print, ' ' print, 'Usage: IDL> anim2cine, shot=130372, /verb, t1=.25,.t2=4 print, ' or: IDL> anim2cine, file1, file2, /verb, t1=.25,.t2=4 return endif delim = get_delim() ;;;if n_elements( label1 ) eq 0 then label1 = 'Monochrome' if n_elements( label2 ) eq 0 then begin if strpos( strupcase(file2), 'MIRO') ge 0 then begin label2 = 'Color' endif else begin wordarray, dir2, words, delim=delim label2 = words[ n_elements(words)-1] endelse endif if n_elements( label1 ) eq 0 then begin if label2 eq 'Color' then begin label1 = 'Monochrome' endif else begin wordarray, dir1, words, delim=delim label1 = words[ n_elements(words)-1] endelse endif ; open .cin files and determine times CINE_TIME, file1, cine1Times, firstImage = FirstFrameFile1, status=status if not status then begin print, ' *** could not read times from file '+file1 return endif print, ' >>> for cine Times in file1:' minmax, cine1Times dts1 = cine1Times[1:*] - cine1Times[0:*] CINE_TIME, file2, cine2Times, firstImage = FirstFrameFile2, status=status if not status then begin print, ' *** could not read times from file '+file2 return endif print, ' >>> for cine Times in file2:' minmax, cine2Times dts2 = cine2Times[1:*] - cine2Times[0:*] ; want the second file to be the slower one if dts2[0] lt dts1[0] then begin if verbose then print, ' >>> swapping 1st & 2nd files, so faster one is first' file1 = file2_in[0] file2 = file1_in[0] CINE_TIME, file1, cine1Times, firstImage = FirstFrameFile1 CINE_TIME, file2, cine2Times, firstImage = FirstFrameFile2 endif if n_elements( max1 ) eq 0 then begin if strpos( STRUPCASE(file1), 'MIRO') ge 0 $ then max1 = 2L^10 - 1 $ else max1 = 2L^14 - 1 ;;; max1 = 2L^bitcount1 - 1 endif if n_elements( max2 ) eq 0 then begin if strpos( STRUPCASE(file2), 'MIRO') ge 0 $ then max2 = 2L^10 - 1 $ else max2 = 2L^14 - 1 ;;; max2 = 2L^bitcount2 - 1 endif ; limit movie to common times within both files minTimes1 = MIN( cine1times, MAX=maxTimes1 ) minTimes2 = MIN( cine2times, MAX=maxTimes2 ) minTime = minTimes1 > minTimes2 maxTime = maxTimes1 < maxTimes2 t1 = t1_in > minTime if n_elements(t2_in) eq 0 then t2_in = t1 ; just do one time, if t2 not entered t2 = t2_in < maxtime inds1ClosestTo2 = NEARESTI_ARRAY( cine1Times, cine2Times ) inds2ClosestTo1 = NEARESTI_ARRAY( cine2Times, cine1Times ) ; cineload uses a COMMON block, so can't be used for 2 files simultaneously ; cineLoadSimple does not use COMMON blocks, but is slower cine1Img= CINELOAD( file1, NEARESTI(cine1Times,t1), $ pps, exposure, bitcount=bitcount1, $ verbose=verbose, status=status ) if verbose then print, 'Bitcount for file1=', bitcount1 info = SIZE( cine1Img ) IF info[0] eq 2 THEN BEGIN TrueColor1 = 0 cine1Width = info[1] cine1Ht = info[2] ENDIF ELSE IF info[0] eq 3 AND info[1] eq 3 THEN BEGIN TrueColor1 = 1 cine1Width = info[2] cine1Ht = info[3] ENDIF ELSE BEGIN Message, 'Frame from file1 is not 2D' STOP ENDELSE cine2Img= CINELOAD2( file2, NEARESTI(cine2Times,t1), $ pps, exposure, bitcount=bitcount2, $ verbose=verbose, status=status ) if verbose then print, 'Bitcount for file2=', bitcount2 info = SIZE( cine2Img ) IF info[0] eq 2 THEN BEGIN TrueColor2 = 0 cine2Width = info[1] cine2Ht = info[2] ENDIF ELSE IF info[0] eq 3 AND info[1] eq 3 THEN BEGIN TrueColor2 = 1 cine2Width = info[2] cine2Ht = info[3] ENDIF ELSE BEGIN Message, 'Frame from file2 is not 2D' STOP ENDELSE if cine1Width le cine2Width/2 then begin mag1 = cine2Width/cine1Width cine1Width = cine1Width * mag1 cine1Ht = cine1Ht* mag1 if cine1Width le 128 then begin mag1 = 256/cine1Width cine1Width = cine1Width * mag1 cine1Ht = cine1Ht* mag1 endif endif if cine2Width le cine1Width/2 then begin mag2 = cine1Width/cine2Width cine2Width = cine2Width * mag2 cine2Ht = cine2Ht* mag2 if cine2Width le 128 then begin mag2 = 256/cine2Width cine2Width = cine2Width * mag1 cine2Ht = cine2Ht* mag1 endif endif ; Load current color table into byte arrays TVLCT, red, green, blue, /GET if n_elements( xsize ) gt 0 then mpegWidth = xsize $ else mpegWidth = cine1Width + cine2Width + 3*border if n_elements( ysize ) gt 0 then mpegHt = ysize $ else mpegHt = (cine2Ht > cine1Ht) + 2*border + topPixels + botPixels if oddnumber( mpegWidth ) then mpegWidth = mpegWidth +1 if oddnumber( mpegHt ) then mpegHt = mpegHt +1 if verbose then print, 'MPEG width and heighth=', mpegWidth, mpegHt ; output filename if n_elements( outFile ) eq 0 then begin if n_elements( shot ) eq 0 then begin shotStr1 = extractshotnumber( file1 ) shotStr2 = extractshotnumber( file2 ) if shotStr1 ne shotStr2 then begin beep print, '*** shot numbers extracted from filenames not the same' endif if shotStr1 ne -1 then shot = shotStr1 else shot = shotStr2 endif if long( shot ) lt 0 then shot = 999999 t1str = STRING(ROUND(t1*1000), FORMAT='(I4.4)') t2str = STRING(ROUND(t2*1000), FORMAT='(I4.4)') outFile = prefix + strcompress(shot,/remove_all) + '_' + $ t1str + '_' + t2str + 'ms' + '.'+type endif if nwords( outDir ) gt 0 then begin delim = get_delim() if lastChar( outDir ) ne delim then outDir = outDir+delim ; make sure directory not already in filename if strpos( outFile, outDir ) lt 9 then outFile = outDir + outFile endif if verbose then print, 'outFile=', outFile found = file_test( outFile ) if found then begin result = 'Y' if dialog then result = dialog_input( $ prompt=outFile+' exists! Do you want to delete it first?') if STRUPCASE( result ) NE 'Y' then return file_delete, outFile endif FDECOMP, outFile, disk, dir, name, ext if nwords( ext ) eq 0 then outFile = outFile+'.'+type if n_elements( ctb ) eq 0 then ctb = 0 ; Lane says grayscale shows the most cStr = mk_color( table=ctb, /load, max=256, N_NONFIXED=ncolors ) if view then window, xsize=mpegWidth, ysize=mpegHt, xpos=50, ypos=50 SET_PLOT, 'Z' Device, set_resolution=[mpegWidth,mpegHt] ch_siz=2 if n_elements( thick ) eq 0 then thick=2 ;;;if NOT debug then stat = ANIM_OPEN( outFile, mpegWidth, mpegHt, type=type ) if NOT view then mpegID = MPEG_OPEN( [mpegWidth, mpegHt] ) y0 = botPixels x1 = border x2 = border*2 + cine1Width iCineFastT1 = nearesti( cine1times, t1 ) nFastFrames = nearesti( cine1times, t2 ) - iCineFastT1 + 1 if not view then begin TVLCT, RED, GREEN, BLUE, /GET fullImage24 = BYTARR(3,mpegWidth, mpegHt ) ; for inserting full image into color array xf1 = x2 xf2 = x2 + cine2Width-1 yf1 = y0 yf2 = y0 + cine2Ht-1 endif ifr=0 lastSlowFrame = -1 FOR iCine = 0, nFastFrames*inc-inc, inc DO BEGIN if iCine gt (nFastFrames-1) then break ; get image from faster camera iFast = iCine+iCineFastT1 cine1Img = CINELOAD( file1, iFast, pps, exposure, $ verbose=verbose, status=status ) if not status then begin print, ' *** bad status on file1' stop endif cine1Min = MIN( cine1Img, MAX=cine1Max ) if mag1 gt 1 then cine1Img = REBIN(cine1Img, cine1Width, cine1Ht) if verbose then print, 'iFast, cine1Min, cine1Max=', iFast, cine1Min, cine1Max if N_ELEMENTS( gamma1 ) gt 0 then cine1Img = GAMMA_RAISE(cine1Img, gamma1) cine1Img = bytscl( cine1Img, top=ncolors, max=max1 ) if nsmooth gt 1 then cine1Img = amedian( cine1Img, nsmooth ) if view then begin ; if viewing in 'X', need to set back to Z buffer to form plot SET_PLOT, 'Z' Device, set_resolution=[mpegWidth,mpegHt] endif erase, color=cStr.black tv, cine1Img, x1, y0, true=trueColor1 xyouts, x1, border, label1, /device, charsize=charsize, align=0, color=cStr.white C1Time = cine1Times[iFast] timeStr = string(C1Time*1000, format='(f9.3)') ; output milliseconds xyouts, x1+5+strlen(label1)*charsize*!d.x_ch_size, border, timeStr + ' ms', $ charsize=charsize, color=cStr.green, /device ; top ; get image from slower camera iSlow = inds2ClosestTo1[ iFast ] if iSlow ne lastSlowFrame then begin cine2Img = CINELOAD2( file2, iSlow, pps, exposure, $ verbose=verbose, status=status ) if not status then begin print, ' *** bad status on file2' stop endif cine2Min = MIN( cine2Img, MAX=cine2Max ) if verbose then print, 'islow, cine2Min, cine2Max=', $ islow, cine2Min, cine2Max, cine2Times[iSlow], ' s' if mag2 gt 1 then cine2Img = REBIN(cine2Img, cine2Width, cine2Ht) ;;; if view then cine2Img = bytscl( cine2Img, top=ncolors, max=max2 ) $ top = ncolors if TrueColor2 then top=255 if N_ELEMENTS( gamma2 ) gt 0 then cine2Img = GAMMA_RAISE(cine2Img, gamma2) if view then cine2Img = bytscl( cine2Img, top=top, max=max2 ) $ else cine2Img = bytscl( cine2Img, top=top, max=max2 ) if nsmooth gt 1 then cine2Img = amedian( cine2Img, nsmooth ) lastSlowFrame = iSlow endif xyouts, x2+!d.x_ch_size*2, border, label2, /device, charsize=charsize, $ align=0, color=cStr.white C2Time = cine2Times[iSlow] timeStr = string(C2Time*1000, format='(f9.3)') ; output milliseconds xyouts, x2+!d.x_ch_size*2+5+strlen(label2)*charsize*!d.x_ch_size, $ border, timeStr + ' ms', $ charsize=charsize, color=cStr.green, /device ; top NSTXLOGO, blue=cStr.blue, red=cStr.red, charthick=1.5 ; thicker for mpeg ; when image saturated, hard to see green text: FANCY_TITLE,'Shot '+strtrim(shot,2), charthick=1.3, charsize=2, $ charColor=cStr.white, line=0.5 if view then begin img = TVRD() set_plot,'x' tv, img tv, cine2Img, x2, y0, true=trueColor2 if debug then stop endif else begin if trueColor2 then begin img = TVRD( ) fullImage24(0,*,*) = RED(img(*,*)) fullImage24(1,*,*) = GREEN(img(*,*)) fullImage24(2,*,*) = BLUE(img(*,*)) ; now insert full-color image into color array fullImage24(0,xf1:xf2,yf1:yf2) = cine2Img(0,*,*) fullImage24(1,xf1:xf2,yf1:yf2) = cine2Img(1,*,*) fullImage24(2,xf1:xf2,yf1:yf2) = cine2Img(2,*,*) endif else begin tv, cine2Img, x2, y0, true=trueColor2 img = TVRD( ) fullImage24(0,*,*) = RED(img(*,*)) fullImage24(1,*,*) = GREEN(img(*,*)) fullImage24(2,*,*) = BLUE(img(*,*)) endelse ;;; ANIM_WRITE, img, FRAME=ifr, ndups=ndups, /verbose for j=0,ndups do begin ; duplicate frames to slow down mpeg MPEG_PUT, mpegID, image=fullImage24, FRAME=ifr, order=1 ifr = ifr + 1 endfor endelse ENDFOR print, ' ' print, ' >> Done processing files '+file1+' and '+file2 print, ' ' ; Close the animation file: ;;;if NOT debug then ANIM_CLOSE if NOT view then begin print, ' (saving animation file '+outFile+'; this may take a long time!)' MPEG_SAVE, mpegID, filename=outFile MPEG_CLOSE, mpegID print, 'Done writing animation file '+outfile endif ;;;if not debug then device, z_buffer=1 set_plot, 'X' beep if debug then stop RETURN badWrite: alert, 'Unable to write MPEG/AVI file!' stop END