笔者学识有限。 本博客旨在对mitre_sfr核心代码进行简单注解, 详细内容读者仁者见仁智者见智。
本人最近有幸拜读mitre_sfr代码, 对代码进行了简单的注解。介于学习的时候在网上没搜到类似的文章,所以特开立这个主题, 希望对后面学习mitre_sfr或想了解SFR算法的同学有所帮助。
另外, 本人是计科生, 对信号与系统知识了解有限, 读代码的时候也有一些不甚了解之处, 在代码注解中进行了标注, 希望相关领域大神在浏览的时候能顺便帮我解惑, 在此不甚感激。
拜读mitre_sfr代码时发现mitre_sfr的源码和ISO12233附录A中的代码出奇的一致, 相似性达到至少90%, 说明mitre_sfr作者对IOS的作者出于崇高的敬意。
废话少说, 贴代码。
看代码先看主干, 我先贴main函数。 Mitre_sfr的main函数对核心算法和主干涉及不多, 仅涉及sfr计算的预处理和sfr计算结果输出的一些处理, 建议大家快速阅读即可。
下一篇我将先贴出mitre_sfr最核心的函数sfrProc的源码和注解。 其他次要代码及注解在后续文章贴出, 希望大家体谅。
int main(int argc, char **argv)
{
char problem_string[82];
unsigned char rotation;
int i;
double *farea;
double slope, scale, b;
int size_x, size_y;
int len, err, bin_len;
int rgt_side, left_side;
int center;
int numcycles=0;
double *Freq=NULL;
double *disp=NULL;
double *ref_lut;
double off, R2;
int center_x, center_y, new_x, new_y;
int lowest_val, highest_val, grey_level, first, last;
int piv_err;
TIFF* tif = NULL;
#if !defined(MSDOS)
char *fnamep;
fnamep = dirname(argv[0]);
if (argc==1 && fnamep != NULL && fnamep[0] == '/') {
printf ("Changed to directory of executable: %s\n\n", fnamep);
chdir((const char *)fnamep);
}
#else
atexit(wait_to_exit);
#endif
/* Once-only initializations */
g_scan_image_file_id = 0;
g_problem_count = 0; /* # of problems in our problem report */
g_IQS_problem_count = 0;
get_switches(argc, argv, image_filename, data_filename);
/* always append output to this file */
if ((g_mtfout = fopen(MTFOUTNAME,"a")) == NULL) {
fprintf(stderr,"Can't open %s\n",MTFOUTNAME);
exit(1);
}
/* command line args */
get_args(image_filename,data_filename,&tif); // 获取源文件名并读取文件头, 获取ROI位置, 如果需要读取计算角度的两个点位
/* print the user entered data (corner coords, etc.) in the output */
/* 时间, 版本号, 以及get_args函数里面获取到的信息*/
print_header(image_filename,data_filename);
g_target_res = 500;
if (abs((int)g_ppi - g_target_res) > 10) {
sprintf(problem_string,
"Resolution outside the %d-%d ppi PIV spec range\n",
g_target_res-10,g_target_res+10);
put_problem(problem_string, IQS);
put_problem("\n", IQS);
}
// 从ROI 4个角落各读取4个像素点, 用于判断刀口方向, 并确认ROI区域的合法性
input_area(tif, &rotation,
g_test_pattern_yul, g_test_pattern_ylr,
g_test_pattern_xul, g_test_pattern_xlr);
/* read the image in - we store it internally in a standard way */
// 读取ROI图像, 如果并将水平刀口转换为垂直刀口
read_in_image(tif,rotation,image_filename,&size_x,&size_y);
/* get reflectance */
// 创建反射查找表, 将图像灰阶映射在0~1范围内
ref_lut = read_in_ref_lut(data_filename, &lowest_val, &highest_val);
// 将原图ROI映射到反射ROI
len = size_x*size_y;
farea = (double *)malloc(len*sizeof(double));
for(i=0; i highest_val) {
MTFPRINT("ERROR: OECF range does not cover the entire image\n")
MTFPRINT2(" Greylevel %d found in image, but not OECF\n", grey_level)
exit(-1);
}
farea[i] = (double)ref_lut[grey_level];
}
if(g_autorefine) {
find_area(farea, (unsigned short)size_x, (unsigned short)size_y, &new_x, &new_y, ¢er_x, ¢er_y, g_extended);
if (new_x != size_x || new_y != size_y ||
center_x != size_x/2 || center_y != size_y/2) {
center_x += (g_test_pattern_xlr + g_test_pattern_xul)/2 - size_x/2;
center_y += (g_test_pattern_ylr + g_test_pattern_yul)/2 - size_y/2;
g_test_pattern_xul = center_x - new_x/2;
g_test_pattern_yul = center_y - new_y/2;
g_test_pattern_xlr = g_test_pattern_xul + new_x;
g_test_pattern_ylr = g_test_pattern_yul + new_y;
read_in_image(tif,rotation,image_filename,&size_x,&size_y);
len = size_x*size_y;
for(i=0; i= size_x-2 ) {
MTFPRINT("** ERROR: User specified edge does not work with ROI **\n");
if (off-fslope < 2)
MTFPRINT3("Edge Angle = %.3f degrees located %d pixels before ROI\n",
(atan(slope)*(double)(180.0/M_PI)), (int)rint(off))
else
MTFPRINT3("Edge Angle = %.3f degrees located %d pixels after ROI\n",
(atan(slope)*(double)(180.0/M_PI)), (int)rint(off-size_x))
if (g_debug) {
MTFPRINT("See location of edge points in diagnostic image\n")
write_debug_image(g_debug_array,g_debug_fullwidth, g_debug_fullheight);
}
exit(-1);
}
}
// 计算ROI中超出取值范围[0, 255]外的像素比例
// 前面像素映射的时候已经逐点确认过是否所有像素在oecf范围内, 感觉这个函数没什么实际作用
clipping (0, 255, 0.02, g_image_array, len);
/* calculate the sfr on this area */
err = sfrProc(&Freq, &disp, &bin_len, farea, (unsigned short)size_x, &size_y, &slope, &numcycles,¢er,&off, &R2, g_version, 0, g_userangle);
/* Add messages to problem report */
slope_bounds( slope, size_y, numcycles, 5.0, problem_string);
if(g_debug) {
draw_lines(g_debug_array, slope, rotation, center, size_y, off, size_x);
write_debug_image(g_debug_array,g_debug_fullwidth, g_debug_fullheight);
}
if (!g_userangle)
MTFPRINT2("R2 of linear edge fit = %.3f\n", R2)
else
MTFPRINT("User input edge location: No R2 available\n")
MTFPRINT4("Edge Angle = %.3f degrees \nCycle Length = %.3f \t#Cycles = %d\n",
(atan(slope)*(double)(180.0/M_PI)), fabs(1.0/slope), numcycles )
left_side = size_x/2+off; rgt_side = size_x/2-off;
if (left_side > bin_len/4) left_side = bin_len/4;
if (rgt_side > bin_len/4) rgt_side = bin_len/4;
MTFPRINT2("SFR computed using ~%d pixels on left or top side of the edge,\n", left_side)
MTFPRINT2(" and ~%d pixels on right or bottom side of the edge,\n", rgt_side)
MTFPRINT(" all within the ROI\n")
if (rotation == RIGHT)
MTFPRINT3(" over %d rows, centered at row %d\n", size_y, (g_test_pattern_yul + g_test_pattern_ylr)/2 )
else
MTFPRINT3(" over %d cols, centered at col %d\n", size_y, (g_test_pattern_xul + g_test_pattern_xlr)/2 )
if (center/4 < 16) {
MTFPRINT("\nERROR: Too few pixels across the edge for valid SFR computation\n\n")
exit(-1);
}
if ( left_side < 20 || rgt_side < 20)
MTFPRINT("Warning: Low width across the edge. SFR values may be suspect.\n")
/* log any problems we encountered into output */
if (g_reversepolarity)
MTFPRINT("\nNOTE: Original image polarity was reversed by user request.\n")
if (err) {
MTFPRINT ("** ERROR in computation. SFR values unknown **\n\n")
exit(-1);
}
scale = g_ppi/MM_PER_INCH;
MTFPRINT("\n\ncy/mm \t SFR ")
if(rotation == RIGHT)
MTFPRINT("\t Vert ")
else
MTFPRINT("\t Horz ")
if(farea[4*size_x-1] - farea[0] > 0)
MTFPRINT("black-to-white** edge\n(obj.plane)\n")
else
MTFPRINT("white-to-black** edge\n(obj.plane)\n")
piv_err=0;
for( i=0; i 0.5)
MTFPRINT("\t#\n") /* Mark frequencies above Nyquist */
else {
double lower = 1.02829 - 1.67473e-1*f + 1.06255e-2*f*f - 2.80874e-4*f*f*f;
double upper = 1.12;
if ((f<=10 && f >= 0.998) && (sfr < lower || sfr > upper)) {
if (g_nocompare)
MTFPRINT("\n")
else {
piv_err = 1;
MTFPRINT("\t*\n") /* Mark out of PIV spec values */
}
sprintf(problem_string,
"Computed SFR at %.3f cy/mm is outside PIV spec range of %.3f - %.2f\n",
f,lower,upper);
put_problem(problem_string, IQS);
}
else MTFPRINT("\n")
}
}
MTFPRINT("\n# Frequencies above Nyquist\n")
if (piv_err)
MTFPRINT("\n* SFR is outside PIV spec. See problem report for details.\n")
first = reverse_lut(ref_lut, farea[0], lowest_val, highest_val);
last = reverse_lut(ref_lut, farea[4*size_x-1], lowest_val, highest_val);
if (rotation == RIGHT) {
MTFPRINT2("** Edge type based on leftside gray level (%d)\n", first)
MTFPRINT2(" and rightside gray level (%d)\n", last)
}
else {
MTFPRINT2("** Edge type based on top gray level (%d)\n", first)
MTFPRINT2(" and bottom gray level (%d)\n", last)
}
MTFPRINT(" If type isn't correct, use 'f' option to adjust polarity\n\n")
print_problems();
if (g_extended){
int offset, begin, end;
int j, cnt;
double threshold,max_edge,current;
/* Derivatives below this value is considered insignificant for printing */
max_edge = fabs(farea[4*size_x+bin_len]);
threshold = max_edge / 25.0;
/* Find 5 contiguous insignificant values first occur before center */
offset = center - bin_len;
j = bin_len; cnt = 0;
while (cnt < 5 && j>=0) {
current = fabs(farea[4*size_x+j]);
if ( current < threshold ) cnt ++;
else cnt = 0;
if (current > max_edge) max_edge = current;
j--;
}
if (j<0) j=0;
begin = j + offset;
/* Find 5 contiguous insignificant values first occur after center */
j = bin_len; cnt = 0;
while (cnt < 5 && j max_edge) max_edge = current;
j++;
}
if (j==2*bin_len) j=2*bin_len-1;
end = j + offset;
if ( farea[4*size_x+bin_len] < 0 ) max_edge *= -1;
MTFPRINT("\n\nPixel+ \t\t LSF_w \t\t AvgESF")
if (g_version&4)
MTFPRINT(" \t \n")
else
MTFPRINT("(with -0.125 offset)\n")
for( i=begin, j=begin-offset; i<0; j++, i++)
MTFPRINT3("% .2f \t\t% f\n", (i-center)/4.0, farea[4*size_x + j]/max_edge)
for( ; i