You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							999 lines
						
					
					
						
							28 KiB
						
					
					
				
			
		
		
	
	
							999 lines
						
					
					
						
							28 KiB
						
					
					
				| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
|  | |
| #define stop() __debugbreak() | |
| #include <windows.h> | |
| #define int64 __int64 | |
|  | |
| #pragma warning(disable:4127) | |
|  | |
| #define STBIR__WEIGHT_TABLES   | |
| #define STBIR_PROFILE | |
| #define STB_IMAGE_RESIZE_IMPLEMENTATION | |
| #include "stb_image_resize2.h"   | |
|  | |
| static int * file_read( char const * filename ) | |
| { | |
|   size_t s; | |
|   int * m; | |
|   FILE * f = fopen( filename, "rb" ); | |
|   if ( f == 0 ) return 0; | |
|    | |
|   fseek( f, 0, SEEK_END); | |
|   s = ftell( f ); | |
|   fseek( f, 0, SEEK_SET); | |
|   m = malloc( s + 4 ); | |
|   m[0] = (int)s; | |
|   fread( m+1, 1, s, f); | |
|   fclose(f); | |
| 
 | |
|   return( m ); | |
| } | |
| 
 | |
| typedef struct fileinfo | |
| { | |
|   int * timings; | |
|   int timing_count; | |
|   int dimensionx, dimensiony; | |
|   int numtypes; | |
|   int * types; | |
|   int * effective; | |
|   int cpu; | |
|   int simd; | |
|   int numinputrects; | |
|   int * inputrects; | |
|   int outputscalex, outputscaley; | |
|   int milliseconds; | |
|   int64 cycles; | |
|   double scale_time; | |
|   int bitmapx, bitmapy; | |
|   char const * filename; | |
| } fileinfo; | |
| 
 | |
| int numfileinfo; | |
| fileinfo fi[256]; | |
| unsigned char * bitmap; | |
| int bitmapw, bitmaph, bitmapp; | |
| 
 | |
| static int use_timing_file( char const * filename, int index ) | |
| { | |
|   int * base = file_read( filename ); | |
|   int * file = base; | |
| 
 | |
|   if ( base == 0 ) return 0; | |
| 
 | |
|   ++file; // skip file image size; | |
|   if ( *file++ != 'VFT1' ) return 0; | |
|   fi[index].cpu = *file++; | |
|   fi[index].simd = *file++; | |
|   fi[index].dimensionx = *file++; | |
|   fi[index].dimensiony = *file++; | |
|   fi[index].numtypes = *file++; | |
|   fi[index].types = file; file += fi[index].numtypes; | |
|   fi[index].effective = file; file += fi[index].numtypes; | |
|   fi[index].numinputrects = *file++; | |
|   fi[index].inputrects = file; file += fi[index].numinputrects * 2; | |
|   fi[index].outputscalex = *file++; | |
|   fi[index].outputscaley = *file++; | |
|   fi[index].milliseconds = *file++; | |
|   fi[index].cycles = ((int64*)file)[0]; file += 2; | |
|   fi[index].filename = filename; | |
| 
 | |
|   fi[index].timings = file; | |
|   fi[index].timing_count = (int) ( ( base[0] - ( ((char*)file - (char*)base - sizeof(int) ) ) ) / (sizeof(int)*2) ); | |
| 
 | |
|   fi[index].scale_time = (double)fi[index].milliseconds / (double)fi[index].cycles; | |
| 
 | |
|   return 1; | |
| } | |
| 
 | |
| static int vert_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int ox, int oy, int ix, int iy, int filter, STBIR__V_FIRST_INFO * v_info ) | |
| { | |
|   float h_scale=(float)ox/(float)(ix); | |
|   float v_scale=(float)oy/(float)(iy); | |
|   stbir__support_callback * support = stbir__builtin_supports[filter]; | |
|   int vertical_filter_width = stbir__get_filter_pixel_width(support,v_scale,0); | |
|   int vertical_gather = ( v_scale >= ( 1.0f - stbir__small_float ) ) || ( vertical_filter_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT ); | |
| 
 | |
|   return stbir__should_do_vertical_first( weights_table, stbir__get_filter_pixel_width(support,h_scale,0), h_scale, ox, vertical_filter_width, v_scale, oy, vertical_gather, v_info ); | |
| }  | |
| 
 | |
| #define STB_IMAGE_WRITE_IMPLEMENTATION | |
| #include "stb_image_write.h" | |
|  | |
| static void alloc_bitmap() | |
| { | |
|   int findex; | |
|   int x = 0, y = 0; | |
|   int w = 0, h = 0; | |
| 
 | |
|   for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|   { | |
|     int nx, ny; | |
|     int thisw, thish; | |
| 
 | |
|     thisw = ( fi[findex].dimensionx * fi[findex].numtypes ) + ( fi[findex].numtypes - 1 ); | |
|     thish = ( fi[findex].dimensiony * fi[findex].numinputrects ) + ( fi[findex].numinputrects - 1 ); | |
| 
 | |
|     for(;;) | |
|     { | |
|       nx = x + ((x)?4:0) + thisw; | |
|       ny = y + ((y)?4:0) + thish; | |
|       if ( ( nx <= 3600 ) || ( x == 0 ) ) | |
|       {  | |
|         fi[findex].bitmapx = x + ((x)?4:0); | |
|         fi[findex].bitmapy = y + ((y)?4:0); | |
|         x = nx; | |
|         if ( x > w ) w = x; | |
|         if ( ny > h ) h = ny; | |
|         break; | |
|       } | |
|       else | |
|       { | |
|         x = 0; | |
|         y = h; | |
|       } | |
|     } | |
|   } | |
| 
 | |
|   w = (w+3) & ~3; | |
|   bitmapw = w; | |
|   bitmaph = h; | |
|   bitmapp = w * 3; // RGB | |
|   bitmap = malloc( bitmapp * bitmaph ); | |
| 
 | |
|   memset( bitmap, 0, bitmapp * bitmaph ); | |
| } | |
| 
 | |
| static void build_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index, int findex ) | |
| { | |
|   static int colors[STBIR_RESIZE_CLASSIFICATIONS]; | |
|   STBIR__V_FIRST_INFO v_info = {0}; | |
| 
 | |
|   int * ts; | |
|   int ir; | |
|   unsigned char * bitm = bitmap + ( fi[findex].bitmapx*3 ) + ( fi[findex].bitmapy*bitmapp) ; | |
| 
 | |
|   for( ir = 0; ir < STBIR_RESIZE_CLASSIFICATIONS ; ir++ ) colors[ ir ] = 127*ir/STBIR_RESIZE_CLASSIFICATIONS+128; | |
| 
 | |
|   ts = fi[findex].timings; | |
| 
 | |
|   for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ ) | |
|   { | |
|     int ix, iy, chanind; | |
|     ix = fi[findex].inputrects[ir*2]; | |
|     iy = fi[findex].inputrects[ir*2+1]; | |
| 
 | |
|     for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ ) | |
|     { | |
|       int ofs, h, hh; | |
| 
 | |
|       // just do the type that we're on | |
|       if ( chanind != do_channel_count_index ) | |
|       { | |
|         ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony; | |
|         continue; | |
|       } | |
| 
 | |
|       // bitmap offset | |
|       ofs=chanind*(fi[findex].dimensionx+1)*3+ir*(fi[findex].dimensiony+1)*bitmapp; | |
| 
 | |
|       h = 1; | |
|       for( hh = 0 ; hh < fi[findex].dimensiony; hh++ ) | |
|       { | |
|         int ww, w = 1; | |
|         for( ww = 0 ; ww < fi[findex].dimensionx; ww++ ) | |
|         { | |
|           int good, v_first, VF, HF; | |
| 
 | |
|           VF = ts[0]; | |
|           HF = ts[1]; | |
| 
 | |
|           v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); | |
| 
 | |
|           good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first))); | |
| 
 | |
|           if ( good ) | |
|           { | |
|             bitm[ofs+2] = 0; | |
|             bitm[ofs+1] = (unsigned char)colors[v_info.v_resize_classification]; | |
|           } | |
|           else | |
|           { | |
|             double r; | |
| 
 | |
|             if ( HF < VF ) | |
|               r = (double)(VF-HF)/(double)HF; | |
|             else | |
|               r = (double)(HF-VF)/(double)VF; | |
|              | |
|             if ( r > 0.4f) r = 0.4; | |
|             r *= 1.0f/0.4f;    | |
| 
 | |
|             bitm[ofs+2] = (char)(255.0f*r); | |
|             bitm[ofs+1] = (char)(((float)colors[v_info.v_resize_classification])*(1.0f-r)); | |
|           } | |
|           bitm[ofs] = 0; | |
| 
 | |
|           ofs += 3; | |
|           ts += 2; | |
|           w += fi[findex].outputscalex; | |
|         } | |
|         ofs += bitmapp - fi[findex].dimensionx*3; | |
|         h += fi[findex].outputscaley; | |
|       } | |
|     } | |
|   } | |
| } | |
| 
 | |
| static void build_comp_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index ) | |
| { | |
|   int * ts0; | |
|   int * ts1; | |
|   int ir; | |
|   unsigned char * bitm = bitmap + ( fi[0].bitmapx*3 ) + ( fi[0].bitmapy*bitmapp) ; | |
| 
 | |
|   ts0 = fi[0].timings; | |
|   ts1 = fi[1].timings; | |
| 
 | |
|   for( ir = 0 ; ir < fi[0].numinputrects ; ir++ ) | |
|   { | |
|     int ix, iy, chanind; | |
|     ix = fi[0].inputrects[ir*2]; | |
|     iy = fi[0].inputrects[ir*2+1]; | |
| 
 | |
|     for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) | |
|     { | |
|       int ofs, h, hh; | |
| 
 | |
|       // just do the type that we're on | |
|       if ( chanind != do_channel_count_index ) | |
|       { | |
|         ts0 += 2 * fi[0].dimensionx * fi[0].dimensiony; | |
|         ts1 += 2 * fi[0].dimensionx * fi[0].dimensiony; | |
|         continue; | |
|       } | |
| 
 | |
|       // bitmap offset | |
|       ofs=chanind*(fi[0].dimensionx+1)*3+ir*(fi[0].dimensiony+1)*bitmapp; | |
| 
 | |
|       h = 1; | |
|       for( hh = 0 ; hh < fi[0].dimensiony; hh++ ) | |
|       { | |
|         int ww, w = 1; | |
|         for( ww = 0 ; ww < fi[0].dimensionx; ww++ ) | |
|         { | |
|           int v_first, time0, time1; | |
| 
 | |
|           v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, 0 ); | |
| 
 | |
|           time0 = ( v_first ) ? ts0[0] : ts0[1]; | |
|           time1 = ( v_first ) ? ts1[0] : ts1[1]; | |
| 
 | |
|           if ( time0 < time1 ) | |
|           { | |
|             double r = (double)(time1-time0)/(double)time0; | |
|             if ( r > 0.4f) r = 0.4; | |
|             r *= 1.0f/0.4f;    | |
|             bitm[ofs+2] = 0; | |
|             bitm[ofs+1] = (char)(255.0f*r); | |
|             bitm[ofs] = (char)(64.0f*(1.0f-r)); | |
|           } | |
|           else | |
|           { | |
|             double r = (double)(time0-time1)/(double)time1; | |
|             if ( r > 0.4f) r = 0.4; | |
|             r *= 1.0f/0.4f;    | |
|             bitm[ofs+2] = (char)(255.0f*r); | |
|             bitm[ofs+1] = 0; | |
|             bitm[ofs] = (char)(64.0f*(1.0f-r)); | |
|           } | |
|           ofs += 3; | |
|           ts0 += 2; | |
|           ts1 += 2; | |
|           w += fi[0].outputscalex; | |
|         } | |
|         ofs += bitmapp - fi[0].dimensionx*3; | |
|         h += fi[0].outputscaley; | |
|       } | |
|     } | |
|   } | |
| } | |
| 
 | |
| static void write_bitmap() | |
| { | |
|   stbi_write_png( "results.png", bitmapp / 3, bitmaph, 3|STB_IMAGE_BGR, bitmap, bitmapp ); | |
| } | |
| 
 | |
| 
 | |
| static void calc_errors( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int * curtot, double * curerr, int do_channel_count_index ) | |
| { | |
|   int th, findex; | |
|   STBIR__V_FIRST_INFO v_info = {0}; | |
| 
 | |
|   for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++) | |
|   { | |
|     curerr[th]=0; | |
|     curtot[th]=0; | |
|   } | |
| 
 | |
|   for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|   { | |
|     int * ts; | |
|     int ir; | |
|     ts = fi[findex].timings; | |
| 
 | |
|     for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ ) | |
|     { | |
|       int ix, iy, chanind; | |
|       ix = fi[findex].inputrects[ir*2]; | |
|       iy = fi[findex].inputrects[ir*2+1]; | |
| 
 | |
|       for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ ) | |
|       { | |
|         int h, hh; | |
| 
 | |
|         // just do the type that we're on | |
|         if ( chanind != do_channel_count_index ) | |
|         { | |
|           ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony; | |
|           continue; | |
|         } | |
| 
 | |
|         h = 1; | |
|         for( hh = 0 ; hh < fi[findex].dimensiony; hh++ ) | |
|         { | |
|           int ww, w = 1; | |
|           for( ww = 0 ; ww < fi[findex].dimensionx; ww++ ) | |
|           { | |
|             int good, v_first, VF, HF; | |
| 
 | |
|             VF = ts[0]; | |
|             HF = ts[1]; | |
| 
 | |
|             v_first = vert_first( weights_table, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); | |
| 
 | |
|             good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first))); | |
| 
 | |
|             if ( !good ) | |
|             { | |
|               double diff; | |
|               if ( VF < HF ) | |
|                 diff = ((double)HF-(double)VF) * fi[findex].scale_time; | |
|               else | |
|                 diff = ((double)VF-(double)HF) * fi[findex].scale_time; | |
| 
 | |
|               curtot[v_info.v_resize_classification] += 1; | |
|               curerr[v_info.v_resize_classification] += diff; | |
|             } | |
| 
 | |
|             ts += 2; | |
|             w += fi[findex].outputscalex; | |
|           } | |
|           h += fi[findex].outputscaley; | |
|         } | |
|       } | |
|     } | |
|   } | |
| } | |
| 
 | |
| #define TRIESPERWEIGHT 32 | |
| #define MAXRANGE ((TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) - 1) | |
|  | |
| static void expand_to_floats( float * weights, int range ) | |
| { | |
|   weights[0] = (float)( range % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT; | |
|   weights[1] = (float)( range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT; | |
|   weights[2] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT; | |
|   weights[3] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT; | |
| } | |
| 
 | |
| static char const * expand_to_string( int range ) | |
| { | |
|   static char str[128]; | |
|   int w0,w1,w2,w3; | |
|   w0 = range % (TRIESPERWEIGHT+1); | |
|   w1 = range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1); | |
|   w2 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1); | |
|   w3 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1); | |
|   sprintf( str, "[ %2d/%d %2d/%d %2d/%d %2d/%d ]",w0,TRIESPERWEIGHT,w1,TRIESPERWEIGHT,w2,TRIESPERWEIGHT,w3,TRIESPERWEIGHT ); | |
|   return str; | |
| } | |
| 
 | |
| static void print_weights( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index, int * tots, double * errs ) | |
| { | |
|   int th; | |
|   printf("ChInd: %d  Weights:\n",channel_count_index); | |
|   for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++) | |
|   { | |
|     float * w = weights[th]; | |
|     printf("  %d: [%1.5f %1.5f %1.5f %1.5f] (%d %.4f)\n",th, w[0], w[1], w[2], w[3], tots[th], errs[th] ); | |
|   } | |
|   printf("\n"); | |
| } | |
| 
 | |
| static int windowranges[ 16 ]; | |
| static int windowstatus = 0; | |
| static DWORD trainstart = 0; | |
| 
 | |
| static void opt_channel( float best_output_weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index ) | |
| { | |
|   int newbest = 0; | |
|   float weights[STBIR_RESIZE_CLASSIFICATIONS][4] = {0}; | |
|   double besterr[STBIR_RESIZE_CLASSIFICATIONS]; | |
|   int besttot[STBIR_RESIZE_CLASSIFICATIONS]; | |
|   int best[STBIR_RESIZE_CLASSIFICATIONS]={0}; | |
| 
 | |
|   double curerr[STBIR_RESIZE_CLASSIFICATIONS]; | |
|   int curtot[STBIR_RESIZE_CLASSIFICATIONS]; | |
|   int th, range; | |
|   DWORD lasttick = 0; | |
| 
 | |
|   for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)  | |
|   { | |
|     besterr[th]=1000000000000.0; | |
|     besttot[th]=0x7fffffff; | |
|   } | |
| 
 | |
|   newbest = 0; | |
| 
 | |
|   // try the whole range   | |
|   range = MAXRANGE; | |
|   do | |
|   { | |
|     for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++) | |
|       expand_to_floats( weights[th], range ); | |
| 
 | |
|     calc_errors( weights, curtot, curerr, channel_count_index ); | |
| 
 | |
|     for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++) | |
|     { | |
|       if ( curerr[th] < besterr[th] ) | |
|       { | |
|         besterr[th] = curerr[th]; | |
|         besttot[th] = curtot[th]; | |
|         best[th] = range; | |
|         expand_to_floats( best_output_weights[th], best[th] ); | |
|         newbest = 1; | |
|       } | |
|     } | |
| 
 | |
|     { | |
|       DWORD t = GetTickCount(); | |
|       if ( range == 0 ) | |
|         goto do_bitmap; | |
| 
 | |
|       if ( newbest ) | |
|       { | |
|         if ( ( GetTickCount() - lasttick ) > 200 ) | |
|         { | |
|           int findex; | |
|          | |
|          do_bitmap: | |
|           lasttick = t; | |
|           newbest = 0; | |
| 
 | |
|           for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|             build_bitmap( best_output_weights, channel_count_index, findex ); | |
| 
 | |
|           lasttick = GetTickCount(); | |
|         } | |
|       } | |
|     } | |
|     | |
|     windowranges[ channel_count_index ] = range; | |
| 
 | |
|     // advance all the weights and loop | |
|     --range; | |
|   } while( ( range >= 0 ) && ( !windowstatus ) ); | |
| 
 | |
|   // if we hit here, then we tried all weights for this opt, so save them  | |
| } | |
| 
 | |
| static void print_struct( float weight[5][STBIR_RESIZE_CLASSIFICATIONS][4], char const * name ) | |
| { | |
|   printf("\n\nstatic float %s[5][STBIR_RESIZE_CLASSIFICATIONS][4]=\n{", name ); | |
|   { | |
|     int i; | |
|     for(i=0;i<5;i++)  | |
|     {  | |
|       int th; | |
|       for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++) | |
|       { | |
|         int j; | |
|         printf("\n  ");  | |
|         for(j=0;j<4;j++)  | |
|           printf("%1.5ff, ", weight[i][th][j] );  | |
|       } | |
|       printf("\n"); | |
|     } | |
|     printf("\n};\n"); | |
|   } | |
| } | |
| 
 | |
| static float retrain_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4]; | |
| 
 | |
| static DWORD __stdcall retrain_shim( LPVOID p ) | |
| { | |
|   int chanind = (int) (size_t)p; | |
|   opt_channel( retrain_weights[chanind], chanind ); | |
|   return 0; | |
| } | |
| 
 | |
| static char const * gettime( int ms ) | |
| { | |
|   static char time[32]; | |
|   if (ms > 60000) | |
|     sprintf( time, "%dm %ds",ms/60000, (ms/1000)%60 ); | |
|   else   | |
|     sprintf( time, "%ds",ms/1000 ); | |
|   return time; | |
| } | |
| 
 | |
| static BITMAPINFOHEADER bmiHeader; | |
| static DWORD extrawindoww, extrawindowh; | |
| static HINSTANCE instance; | |
| static int curzoom = 1; | |
| 
 | |
| static LRESULT WINAPI WindowProc( HWND   window, | |
|                                   UINT   message, | |
|                                   WPARAM wparam, | |
|                                   LPARAM lparam ) | |
| { | |
|   switch( message ) | |
|   { | |
|     case WM_CHAR: | |
|       if ( wparam != 27 ) | |
|         break; | |
|       // falls through | |
|  | |
|     case WM_CLOSE: | |
|     { | |
|       int i; | |
|       int max = 0; | |
|        | |
|       for( i = 0 ; i < fi[0].numtypes ; i++ ) | |
|         if( windowranges[i] > max ) max = windowranges[i]; | |
|     | |
|       if ( ( max == 0 ) || ( MessageBox( window, "Cancel before training is finished?", "Vertical First Training", MB_OKCANCEL|MB_ICONSTOP ) == IDOK ) ) | |
|       { | |
|         for( i = 0 ; i < fi[0].numtypes ; i++ ) | |
|           if( windowranges[i] > max ) max = windowranges[i]; | |
|         if ( max ) | |
|           windowstatus = 1; | |
|         DestroyWindow( window ); | |
|       } | |
|     } | |
|     return 0; | |
|         | |
|     case WM_PAINT: | |
|     { | |
|       PAINTSTRUCT ps; | |
|       HDC dc; | |
| 
 | |
|       dc = BeginPaint( window, &ps ); | |
|       StretchDIBits( dc,  | |
|         0, 0, bitmapw*curzoom, bitmaph*curzoom, | |
|         0, 0, bitmapw, bitmaph, | |
|         bitmap, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY ); | |
| 
 | |
|       PatBlt( dc, bitmapw*curzoom, 0, 4096, 4096, WHITENESS ); | |
|       PatBlt( dc, 0, bitmaph*curzoom, 4096, 4096, WHITENESS ); | |
| 
 | |
|       SetTextColor( dc, RGB(0,0,0)  ); | |
|       SetBkColor( dc, RGB(255,255,255) ); | |
|       SetBkMode( dc, OPAQUE ); | |
| 
 | |
|       { | |
|         int i, l = 0, max = 0; | |
|         char buf[1024]; | |
|         RECT rc; | |
|         POINT p; | |
| 
 | |
|         for( i = 0 ; i < fi[0].numtypes ; i++ ) | |
|         { | |
|           l += sprintf( buf + l, "channels: %d %s\n", fi[0].effective[i], windowranges[i] ? expand_to_string( windowranges[i] ) : "Done." ); | |
|           if ( windowranges[i] > max ) max = windowranges[i]; | |
|         } | |
| 
 | |
|         rc.left = 32; rc.top = bitmaph*curzoom+10; | |
|         rc.right = 512; rc.bottom = rc.top + 512; | |
|         DrawText( dc, buf, -1, &rc, DT_TOP ); | |
| 
 | |
|         l = 0; | |
|         if ( max == 0 ) | |
|         { | |
|           static DWORD traindone = 0; | |
|           if ( traindone == 0 ) traindone = GetTickCount(); | |
|           l = sprintf( buf, "Finished in %s.", gettime( traindone - trainstart ) ); | |
|         } | |
|         else if ( max != MAXRANGE ) | |
|           l = sprintf( buf, "Done in %s...", gettime( (int) ( ( ( (int64)max * ( (int64)GetTickCount() - (int64)trainstart ) ) ) / (int64) ( MAXRANGE - max ) ) ) ); | |
| 
 | |
|         GetCursorPos( &p ); | |
|         ScreenToClient( window, &p ); | |
| 
 | |
|         if ( ( p.x >= 0 ) && ( p.y >= 0 ) && ( p.x < (bitmapw*curzoom) ) && ( p.y < (bitmaph*curzoom) ) ) | |
|         { | |
|           int findex; | |
|           int x, y, w, h, sx, sy, ix, iy, ox, oy; | |
|           int ir, chanind; | |
|           int * ts; | |
|           char badstr[64]; | |
|           STBIR__V_FIRST_INFO v_info={0}; | |
| 
 | |
|           p.x /= curzoom; | |
|           p.y /= curzoom; | |
| 
 | |
|           for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|           { | |
|             x = fi[findex].bitmapx; | |
|             y = fi[findex].bitmapy; | |
|             w = x + ( fi[findex].dimensionx + 1 ) * fi[findex].numtypes; | |
|             h = y + ( fi[findex].dimensiony + 1 ) * fi[findex].numinputrects; | |
| 
 | |
|             if ( ( p.x >= x ) && ( p.y >= y ) && ( p.x < w ) && ( p.y < h ) ) | |
|               goto found; | |
|           } | |
|           goto nope; | |
|           | |
|          found: | |
|              | |
|           ir = ( p.y - y ) / ( fi[findex].dimensiony + 1 ); | |
|           sy = ( p.y - y ) % ( fi[findex].dimensiony + 1 ); | |
|           if ( sy >= fi[findex].dimensiony ) goto nope; | |
| 
 | |
|           chanind = ( p.x - x ) / ( fi[findex].dimensionx + 1 ); | |
|           sx = ( p.x - x ) % ( fi[findex].dimensionx + 1 ); | |
|           if ( sx >= fi[findex].dimensionx ) goto nope; | |
| 
 | |
|           ix = fi[findex].inputrects[ir*2]; | |
|           iy = fi[findex].inputrects[ir*2+1]; | |
| 
 | |
|           ts = fi[findex].timings + ( ( fi[findex].dimensionx * fi[findex].dimensiony * fi[findex].numtypes * ir ) + ( fi[findex].dimensionx * fi[findex].dimensiony * chanind ) + ( fi[findex].dimensionx * sy ) + sx ) * 2; | |
| 
 | |
|           ox = 1+fi[findex].outputscalex*sx; | |
|           oy = 1+fi[findex].outputscaley*sy; | |
| 
 | |
|           if ( windowstatus != 2 ) | |
|           { | |
|             int VF, HF, v_first, good; | |
|             VF = ts[0]; | |
|             HF = ts[1]; | |
| 
 | |
|             v_first = vert_first( retrain_weights[chanind], ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); | |
| 
 | |
|             good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first))); | |
| 
 | |
|             if ( good ) | |
|               badstr[0] = 0; | |
|             else | |
|             { | |
|               double r; | |
| 
 | |
|               if ( HF < VF ) | |
|                 r = (double)(VF-HF)/(double)HF; | |
|               else | |
|                 r = (double)(HF-VF)/(double)VF; | |
|               sprintf( badstr, " %.1f%% off", r*100 ); | |
|             } | |
|             sprintf( buf + l, "\n\n%s\nCh: %d Resize: %dx%d to %dx%d\nV: %d H: %d  Order: %c (%s%s)\nClass: %d Scale: %.2f %s", fi[findex].filename,fi[findex].effective[chanind], ix,iy,ox,oy, VF, HF, v_first?'V':'H', good?"Good":"Wrong", badstr, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter" ); | |
|           } | |
|           else | |
|           { | |
|             int v_first, time0, time1; | |
|             float (* weights)[4] = stbir__compute_weights[chanind]; | |
|             int * ts1; | |
|             char b0[32], b1[32]; | |
| 
 | |
|             ts1 = fi[1].timings + ( ts - fi[0].timings ); | |
| 
 | |
|             v_first = vert_first( weights, ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info ); | |
| 
 | |
|             time0 = ( v_first ) ? ts[0] : ts[1]; | |
|             time1 = ( v_first ) ? ts1[0] : ts1[1]; | |
|              | |
|             b0[0] = b1[0] = 0; | |
|             if ( time0 < time1 ) | |
|               sprintf( b0," (%.f%% better)", ((double)time1-(double)time0)*100.0f/(double)time0); | |
|             else | |
|               sprintf( b1," (%.f%% better)", ((double)time0-(double)time1)*100.0f/(double)time1); | |
| 
 | |
|             sprintf( buf + l, "\n\n0: %s\n1: %s\nCh: %d Resize: %dx%d to %dx%d\nClass: %d Scale: %.2f %s\nTime0: %d%s\nTime1: %d%s", fi[0].filename, fi[1].filename, fi[0].effective[chanind], ix,iy,ox,oy, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter", time0, b0, time1, b1 ); | |
|           } | |
|         } | |
|        nope: | |
| 
 | |
|         rc.left = 32+320; rc.right = 512+320;  | |
|         SetTextColor( dc, RGB(0,0,128) ); | |
|         DrawText( dc, buf, -1, &rc, DT_TOP ); | |
| 
 | |
|       } | |
|       EndPaint( window, &ps ); | |
|       return 0; | |
|     } | |
| 
 | |
|     case WM_TIMER: | |
|       InvalidateRect( window, 0, 0 ); | |
|       return 0; | |
| 
 | |
|     case WM_DESTROY: | |
|       PostQuitMessage( 0 ); | |
|       return 0; | |
|   } | |
|     | |
| 
 | |
|   return DefWindowProc( window, message, wparam, lparam ); | |
| } | |
| 
 | |
| static void SetHighDPI(void) | |
| { | |
|   typedef HRESULT WINAPI setdpitype(int v); | |
|   HMODULE h=LoadLibrary("Shcore.dll"); | |
|   if (h) | |
|   { | |
|     setdpitype * sd = (setdpitype*)GetProcAddress(h,"SetProcessDpiAwareness"); | |
|     if (sd ) | |
|       sd(1); | |
|   } | |
| }  | |
| 
 | |
| static void draw_window() | |
| { | |
|   WNDCLASS wc; | |
|   HWND w; | |
|   MSG msg; | |
|    | |
|   instance = GetModuleHandle(NULL); | |
| 
 | |
|   wc.style = 0; | |
|   wc.lpfnWndProc = WindowProc; | |
|   wc.cbClsExtra = 0; | |
|   wc.cbWndExtra = 0; | |
|   wc.hInstance = instance; | |
|   wc.hIcon = 0; | |
|   wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |
|   wc.hbrBackground = 0; | |
|   wc.lpszMenuName = 0; | |
|   wc.lpszClassName = "WHTrain"; | |
| 
 | |
|   if ( !RegisterClass( &wc ) ) | |
|     exit(1); | |
| 
 | |
|   SetHighDPI(); | |
| 
 | |
|   bmiHeader.biSize          =  sizeof(BITMAPINFOHEADER); | |
|   bmiHeader.biWidth         =  bitmapp/3; | |
|   bmiHeader.biHeight        =  -bitmaph; | |
|   bmiHeader.biPlanes        =  1; | |
|   bmiHeader.biBitCount      =  24; | |
|   bmiHeader.biCompression   =  BI_RGB; | |
| 
 | |
|   w = CreateWindow( "WHTrain", | |
|                     "Vertical First Training", | |
|                     WS_CAPTION | WS_POPUP| WS_CLIPCHILDREN | | |
|                     WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX, | |
|                     CW_USEDEFAULT,CW_USEDEFAULT, | |
|                     CW_USEDEFAULT,CW_USEDEFAULT, | |
|                     0, 0, instance, 0 ); | |
| 
 | |
|   { | |
|     RECT r, c; | |
|     GetWindowRect( w, &r ); | |
|     GetClientRect( w, &c ); | |
|     extrawindoww = ( r.right - r.left ) - ( c.right - c.left ); | |
|     extrawindowh = ( r.bottom - r.top ) - ( c.bottom - c.top ); | |
|     SetWindowPos( w, 0, 0, 0, bitmapw * curzoom + extrawindoww, bitmaph * curzoom + extrawindowh + 164, SWP_NOMOVE ); | |
|   } | |
| 
 | |
|   ShowWindow( w, SW_SHOWNORMAL ); | |
|   SetTimer( w, 1, 250, 0 ); | |
| 
 | |
|   { | |
|     BOOL ret; | |
|     while( ( ret = GetMessage( &msg, w, 0, 0 ) ) != 0 ) | |
|     {  | |
|       if ( ret == -1 ) | |
|         break; | |
|       TranslateMessage( &msg );  | |
|       DispatchMessage( &msg );  | |
|     } | |
|   } | |
| } | |
| 
 | |
| static void retrain() | |
| { | |
|   HANDLE threads[ 16 ]; | |
|   int chanind; | |
| 
 | |
|   trainstart = GetTickCount(); | |
|   for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) | |
|     threads[ chanind ] = CreateThread( 0, 2048*1024, retrain_shim, (LPVOID)(size_t)chanind, 0, 0 ); | |
| 
 | |
|   draw_window(); | |
| 
 | |
|   for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ ) | |
|   { | |
|     WaitForSingleObject( threads[ chanind ], INFINITE ); | |
|     CloseHandle( threads[ chanind ] ); | |
|   } | |
| 
 | |
|   write_bitmap(); | |
| 
 | |
|   print_struct( retrain_weights, "retained_weights" ); | |
|   if ( windowstatus ) printf( "CANCELLED!\n" ); | |
| } | |
| 
 | |
| static void info() | |
| { | |
|   int findex; | |
| 
 | |
|   // display info about each input file | |
|   for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|   { | |
|     int i, h,m,s; | |
|     if ( findex ) printf( "\n" ); | |
|     printf( "Timing file: %s\n", fi[findex].filename ); | |
|     printf( "CPU type: %d  %s\n", fi[findex].cpu, fi[findex].simd?(fi[findex].simd==2?"SIMD8":"SIMD4"):"Scalar" ); | |
|     h = fi[findex].milliseconds/3600000; | |
|     m = (fi[findex].milliseconds-h*3600000)/60000; | |
|     s = (fi[findex].milliseconds-h*3600000-m*60000)/1000; | |
|     printf( "Total time in test: %dh %dm %ds  Cycles/sec: %.f\n", h,m,s, 1000.0/fi[findex].scale_time ); | |
|     printf( "Each tile of samples is %dx%d, and is scaled by %dx%d.\n", fi[findex].dimensionx,fi[findex].dimensiony, fi[findex].outputscalex,fi[findex].outputscaley ); | |
|     printf( "So the x coords are: " ); | |
|     for( i=0; i < fi[findex].dimensionx ; i++ ) printf( "%d ",1+i*fi[findex].outputscalex ); | |
|     printf( "\n" ); | |
|     printf( "And the y coords are: " ); | |
|     for( i=0; i < fi[findex].dimensiony ; i++ ) printf( "%d ",1+i*fi[findex].outputscaley ); | |
|     printf( "\n" ); | |
|     printf( "There are %d channel counts and they are: ", fi[findex].numtypes ); | |
|     for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%d ",fi[findex].effective[i] ); | |
|     printf( "\n" ); | |
|     printf( "There are %d input rect sizes and they are: ", fi[findex].numinputrects ); | |
|     for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%dx%d ",fi[findex].inputrects[i*2],fi[findex].inputrects[i*2+1] ); | |
|     printf( "\n" ); | |
|   } | |
| } | |
| 
 | |
| static void current( int do_win, int do_bitmap ) | |
| { | |
|   int i, findex; | |
| 
 | |
|   trainstart = GetTickCount(); | |
| 
 | |
|   // clear progress | |
|   memset( windowranges, 0, sizeof( windowranges ) ); | |
|   // copy in appropriate weights | |
|   memcpy( retrain_weights, stbir__compute_weights, sizeof( retrain_weights ) ); | |
| 
 | |
|   // build and print current errors and build current bitmap | |
|   for( i = 0 ; i < fi[0].numtypes ; i++ ) | |
|   { | |
|     double curerr[STBIR_RESIZE_CLASSIFICATIONS]; | |
|     int curtot[STBIR_RESIZE_CLASSIFICATIONS]; | |
|     float (* weights)[4] = retrain_weights[i]; | |
|   | |
|     calc_errors( weights, curtot, curerr, i ); | |
|     if ( !do_bitmap ) | |
|       print_weights( weights, i, curtot, curerr ); | |
| 
 | |
|     for( findex = 0 ; findex < numfileinfo ; findex++ ) | |
|       build_bitmap( weights, i, findex ); | |
|   } | |
| 
 | |
|   if ( do_win ) | |
|     draw_window(); | |
| 
 | |
|   if ( do_bitmap ) | |
|     write_bitmap(); | |
| } | |
| 
 | |
| static void compare() | |
| { | |
|   int i; | |
| 
 | |
|   trainstart = GetTickCount(); | |
|   windowstatus = 2; // comp mode | |
|  | |
|   // clear progress | |
|   memset( windowranges, 0, sizeof( windowranges ) ); | |
| 
 | |
|   if ( ( fi[0].numtypes != fi[1].numtypes ) || ( fi[0].numinputrects != fi[1].numinputrects ) || | |
|        ( fi[0].dimensionx != fi[1].dimensionx ) || ( fi[0].dimensiony != fi[1].dimensiony ) ||  | |
|        ( fi[0].outputscalex != fi[1].outputscalex ) || ( fi[0].outputscaley != fi[1].outputscaley ) ) | |
|   { | |
|    err: | |
|     printf( "Timing files don't match.\n" ); | |
|     exit(5); | |
|   } | |
| 
 | |
|   for( i=0; i < fi[0].numtypes ; i++ ) | |
|   { | |
|     if ( fi[0].effective[i]      != fi[1].effective[i] ) goto err; | |
|     if ( fi[0].inputrects[i*2]   != fi[1].inputrects[i*2] ) goto err; | |
|     if ( fi[0].inputrects[i*2+1] != fi[1].inputrects[i*2+1] ) goto err; | |
|   } | |
|      | |
|   alloc_bitmap( 1 ); | |
|    | |
|   for( i = 0 ; i < fi[0].numtypes ; i++ ) | |
|   { | |
|     float (* weights)[4] = stbir__compute_weights[i]; | |
|     build_comp_bitmap( weights, i ); | |
|   } | |
| 
 | |
|   draw_window(); | |
| } | |
| 
 | |
| static void load_files( char ** args, int count ) | |
| { | |
|   int i; | |
| 
 | |
|   if ( count == 0 ) | |
|   { | |
|     printf( "No timing files listed!" ); | |
|     exit(3); | |
|   } | |
| 
 | |
|   for ( i = 0 ; i < count ; i++ ) | |
|   { | |
|     if ( !use_timing_file( args[i], i ) ) | |
|     { | |
|       printf( "Bad timing file %s\n", args[i] ); | |
|       exit(2); | |
|     } | |
|   } | |
|   numfileinfo = count; | |
| }   | |
| 
 | |
| int main( int argc, char ** argv ) | |
| { | |
|   int check; | |
|   if ( argc < 3 ) | |
|   { | |
|    err: | |
|     printf( "vf_train retrain [timing_filenames....] - recalcs weights for all the files on the command line.\n"); | |
|     printf( "vf_train info [timing_filenames....] - shows info about each timing file.\n"); | |
|     printf( "vf_train check [timing_filenames...] - show results for the current weights for all files listed.\n"); | |
|     printf( "vf_train compare <timing file1> <timing file2> - compare two timing files (must only be two files and same resolution).\n"); | |
|     printf( "vf_train bitmap [timing_filenames...] - write out results.png, comparing against the current weights for all files listed.\n"); | |
|     exit(1); | |
|   } | |
|    | |
|   check = ( strcmp( argv[1], "check" ) == 0 ); | |
|   if ( ( check ) || ( strcmp( argv[1], "bitmap" ) == 0 ) ) | |
|   { | |
|     load_files( argv + 2, argc - 2 ); | |
|     alloc_bitmap( numfileinfo ); | |
|     current( check, !check ); | |
|   } | |
|   else if ( strcmp( argv[1], "info" ) == 0 )  | |
|   { | |
|     load_files( argv + 2, argc - 2 ); | |
|     info(); | |
|   } | |
|   else if ( strcmp( argv[1], "compare" ) == 0 )  | |
|   { | |
|     if ( argc != 4 ) | |
|     { | |
|       printf( "You must specify two files to compare.\n" ); | |
|       exit(4); | |
|     } | |
| 
 | |
|     load_files( argv + 2, argc - 2 ); | |
|     compare(); | |
|   } | |
|   else if ( strcmp( argv[1], "retrain" ) == 0 )  | |
|   { | |
|     load_files( argv + 2, argc - 2 ); | |
|     alloc_bitmap( numfileinfo ); | |
|     retrain();   | |
|   } | |
|   else | |
|   { | |
|     goto err; | |
|   } | |
| 
 | |
|   return 0; | |
| }
 | |
| 
 |