00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <cstring>
00037 #include <climits>
00038
00039 #include "mrcio.h"
00040 #include "portable_fileio.h"
00041 #include "geometry.h"
00042 #include "util.h"
00043 #include "ctf.h"
00044 #include "transform.h"
00045
00046 using namespace EMAN;
00047
00048 const char *MrcIO::CTF_MAGIC = "!-";
00049 const char *MrcIO::SHORT_CTF_MAGIC = "!$";
00050
00051 MrcIO::MrcIO(const string & mrc_filename, IOMode rw)
00052 : filename(mrc_filename), rw_mode(rw), mrcfile(0), mode_size(0),
00053 isFEI(false), is_ri(0), is_new_file(false), initialized(false)
00054 {
00055 memset(&mrch, 0, sizeof(MrcHeader));
00056 is_big_endian = ByteOrder::is_host_big_endian();
00057 }
00058
00059 MrcIO::~MrcIO()
00060 {
00061 if (mrcfile) {
00062 fclose(mrcfile);
00063 mrcfile = 0;
00064 }
00065 }
00066
00067 void MrcIO::init()
00068 {
00069 ENTERFUNC;
00070
00071 if (initialized) {
00072 return;
00073 }
00074
00075 initialized = true;
00076 mrcfile = sfopen(filename, rw_mode, &is_new_file);
00077
00078 if (!is_new_file) {
00079 if (fread(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
00080 throw ImageReadException(filename, "MRC header");
00081 }
00082
00083 if (!is_valid(&mrch)) {
00084 throw ImageReadException(filename, "invalid MRC");
00085 }
00086
00087 is_big_endian = ByteOrder::is_data_big_endian(&mrch.nz);
00088 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00089 swap_header(mrch);
00090 }
00091
00092
00093 mode_size = get_mode_size(mrch.mode);
00094 if(is_complex_mode()) {
00095 is_ri = 1;
00096 }
00097
00098 if (mrch.nxstart != 0 || mrch.nystart != 0 || mrch.nzstart != 0) {
00099 LOGWARN("nx/ny/nz start not zero");
00100 }
00101
00102 if (is_complex_mode()) {
00103 mrch.nx *= 2;
00104 }
00105
00106 if (mrch.xlen == 0) {
00107 mrch.xlen = 1.0;
00108 }
00109
00110 if (mrch.ylen == 0) {
00111 mrch.ylen = 1.0;
00112 }
00113
00114 if (mrch.zlen == 0) {
00115 mrch.zlen = 1.0;
00116 }
00117
00118 if(mrch.nlabels>0) {
00119 if( string(mrch.labels[0],3) == "Fei") {
00120 isFEI = true;
00121 }
00122 }
00123 }
00124 EXITFUNC;
00125 }
00126
00127
00128 bool MrcIO::is_image_big_endian()
00129 {
00130 init();
00131 return is_big_endian;
00132 }
00133
00134 bool MrcIO::is_valid(const void *first_block, off_t file_size)
00135 {
00136 ENTERFUNC;
00137
00138 if (!first_block) {
00139 return false;
00140 }
00141
00142 const int *data = static_cast < const int *>(first_block);
00143 int nx = data[0];
00144 int ny = data[1];
00145 int nz = data[2];
00146 int mrcmode = data[3];
00147 int nsymbt = data[23];
00148
00149 bool data_big_endian = ByteOrder::is_data_big_endian(&nz);
00150
00151 if (data_big_endian != ByteOrder::is_host_big_endian()) {
00152 ByteOrder::swap_bytes(&nx);
00153 ByteOrder::swap_bytes(&ny);
00154 ByteOrder::swap_bytes(&nz);
00155 ByteOrder::swap_bytes(&mrcmode);
00156 ByteOrder::swap_bytes(&nsymbt);
00157 }
00158
00159 if (mrcmode == MRC_SHORT_COMPLEX || mrcmode == MRC_FLOAT_COMPLEX) {
00160 nx *= 2;
00161 }
00162
00163 const int max_dim = 1 << 20;
00164
00165 if ((mrcmode >= MRC_UCHAR && mrcmode < MRC_UNKNOWN) &&
00166 (nx > 1 && nx < max_dim) && (ny > 0 && ny < max_dim) && (nz > 0 && nz < max_dim)) {
00167
00168 if (file_size > 0) {
00169 off_t file_size1 = (off_t)nx * (off_t)ny * (off_t)nz * (off_t)get_mode_size(mrcmode) + (off_t)sizeof(MrcHeader) + nsymbt;
00170 if (file_size == file_size1) {
00171 return true;
00172 }
00173
00174 LOGWARN("image size check fails, still try to read it...");
00175 }
00176 else {
00177 return true;
00178 }
00179
00180 return true;
00181 }
00182 EXITFUNC;
00183 return false;
00184 }
00185
00186 int MrcIO::read_header(Dict & dict, int image_index, const Region * area, bool is_3d)
00187 {
00188 init();
00189
00190 if(isFEI) {
00191 return read_fei_header(dict, image_index, area, is_3d);
00192 }
00193 else {
00194 return read_mrc_header(dict, image_index, area, is_3d);
00195 }
00196 }
00197
00198 int MrcIO::read_mrc_header(Dict & dict, int image_index, const Region * area, bool)
00199 {
00200 ENTERFUNC;
00201
00202
00203 if(image_index < 0) {
00204 image_index = 0;
00205 }
00206 if(image_index != 0) {
00207 throw ImageReadException(filename, "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
00208 }
00209
00210 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file,false);
00211
00212 int xlen = 0, ylen = 0, zlen = 0;
00213 EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00214
00215 dict["nx"] = xlen;
00216 dict["ny"] = ylen;
00217 dict["nz"] = zlen;
00218 dict["MRC.nx"] = mrch.nx;
00219 dict["MRC.ny"] = mrch.ny;
00220 dict["MRC.nz"] = mrch.nz;
00221
00222 dict["datatype"] = to_em_datatype(mrch.mode);
00223
00224 dict["MRC.nxstart"] = mrch.nxstart;
00225 dict["MRC.nystart"] = mrch.nystart;
00226 dict["MRC.nzstart"] = mrch.nzstart;
00227
00228 dict["MRC.mx"] = mrch.mx;
00229 dict["MRC.my"] = mrch.my;
00230 dict["MRC.mz"] = mrch.mz;
00231
00232 dict["MRC.xlen"] = mrch.xlen;
00233 dict["MRC.ylen"] = mrch.ylen;
00234 dict["MRC.zlen"] = mrch.zlen;
00235
00236 dict["MRC.alpha"] = mrch.alpha;
00237 dict["MRC.beta"] = mrch.beta;
00238 dict["MRC.gamma"] = mrch.gamma;
00239
00240 dict["MRC.mapc"] = mrch.mapc;
00241 dict["MRC.mapr"] = mrch.mapr;
00242 dict["MRC.maps"] = mrch.maps;
00243
00244 dict["MRC.minimum"] = mrch.amin;
00245 dict["MRC.maximum"] = mrch.amax;
00246 dict["MRC.mean"] = mrch.amean;
00247 dict["mean"] = mrch.amean;
00248
00249 dict["MRC.ispg"] = mrch.ispg;
00250 dict["MRC.nsymbt"] = mrch.nsymbt;
00251
00252 dict["apix_x"] = mrch.xlen / mrch.mx;
00253 dict["apix_y"] = mrch.ylen / mrch.my;
00254 dict["apix_z"] = mrch.zlen / mrch.mz;
00255
00256 if (area) {
00257 dict["origin_x"] = mrch.xorigin + mrch.xlen * area->origin[0];
00258 dict["origin_y"] = mrch.yorigin + mrch.xlen * area->origin[1];
00259
00260 if (area->get_ndim() == 3 && mrch.nz > 1) {
00261 dict["origin_z"] = mrch.zorigin + mrch.xlen * area->origin[2];
00262 }
00263 else {
00264 dict["origin_z"] = mrch.zorigin;
00265 }
00266 }
00267 else {
00268 dict["origin_x"] = mrch.xorigin;
00269 dict["origin_y"] = mrch.yorigin;
00270 dict["origin_z"] = mrch.zorigin;
00271 }
00272
00273 if (is_complex_mode()) {
00274 dict["is_complex"] = 1;
00275 dict["is_complex_ri"] = 1;
00276 }
00277
00278 dict["MRC.machinestamp"] = mrch.machinestamp;
00279
00280 dict["MRC.rms"] = mrch.rms;
00281 dict["sigma"] = mrch.rms;
00282 dict["MRC.nlabels"] = mrch.nlabels;
00283 for (int i = 0; i < mrch.nlabels; i++) {
00284 char label[32];
00285 sprintf(label, "MRC.label%d", i);
00286 dict[string(label)] = string(mrch.labels[i],80);
00287 }
00288
00289 EMAN1Ctf ctf_;
00290 if(read_ctf(ctf_) == 0) {
00291 vector<float> vctf = ctf_.to_vector();
00292 dict["ctf"] = vctf;
00293 }
00294
00295 Dict dic;
00296 dic.put("type", "imagic");
00297 dic.put("alpha", mrch.alpha);
00298 dic.put("beta", mrch.beta);
00299 dic.put("gamma", mrch.gamma);
00300 dic.put("tx", mrch.xorigin);
00301 dic.put("ty", mrch.yorigin);
00302 dic.put("tz", mrch.zorigin);
00303 Transform * trans = new Transform(dic);
00304 if(zlen<=1) {
00305 dict["xform.projection"] = trans;
00306 }
00307 else {
00308 dict["xform.align3d"] = trans;
00309 }
00310
00311 if(trans) {delete trans; trans=0;}
00312
00313 EXITFUNC;
00314 return 0;
00315 }
00316
00317 int MrcIO::read_fei_header(Dict & dict, int image_index, const Region * area, bool)
00318 {
00319 ENTERFUNC;
00320
00321 if(image_index < 0) {
00322 image_index = 0;
00323 }
00324
00325 if(area && area->get_depth() > 1) {
00326 throw ImageDimensionException("FEI MRC image is 2D tile series, only 2D regional reading accepted.");
00327 }
00328
00329 init();
00330
00331 check_region(area, FloatSize(feimrch.nx, feimrch.ny, feimrch.nz), is_new_file,false);
00332
00333 int xlen = 0, ylen = 0, zlen = 0;
00334 EMUtil::get_region_dims(area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00335
00336 dict["nx"] = xlen;
00337 dict["ny"] = ylen;
00338 dict["nz"] = 1;
00339 dict["FEIMRC.nx"] = feimrch.nx;
00340 dict["FEIMRC.ny"] = feimrch.ny;
00341 dict["FEIMRC.nz"] = feimrch.nz;
00342
00343 dict["datatype"] = to_em_datatype(feimrch.mode);
00344
00345 dict["FEIMRC.nxstart"] = feimrch.nxstart;
00346 dict["FEIMRC.nystart"] = feimrch.nystart;
00347 dict["FEIMRC.nzstart"] = feimrch.nzstart;
00348
00349 dict["FEIMRC.mx"] = feimrch.mx;
00350 dict["FEIMRC.my"] = feimrch.my;
00351 dict["FEIMRC.mz"] = feimrch.mz;
00352
00353 dict["FEIMRC.xlen"] = feimrch.xlen;
00354 dict["FEIMRC.ylen"] = feimrch.ylen;
00355 dict["FEIMRC.zlen"] = feimrch.zlen;
00356
00357 dict["FEIMRC.alpha"] = feimrch.alpha;
00358 dict["FEIMRC.beta"] = feimrch.beta;
00359 dict["FEIMRC.gamma"] = feimrch.gamma;
00360
00361 dict["FEIMRC.mapc"] = feimrch.mapc;
00362 dict["FEIMRC.mapr"] = feimrch.mapr;
00363 dict["FEIMRC.maps"] = feimrch.maps;
00364
00365 dict["FEIMRC.minimum"] = feimrch.amin;
00366 dict["FEIMRC.maximum"] = feimrch.amax;
00367 dict["FEIMRC.mean"] = feimrch.amean;
00368 dict["mean"] = feimrch.amean;
00369
00370 dict["FEIMRC.ispg"] = feimrch.ispg;
00371 dict["FEIMRC.nsymbt"] = feimrch.nsymbt;
00372
00373 dict["apix_x"] = feimrch.xlen / feimrch.mx;
00374 dict["apix_y"] = feimrch.ylen / feimrch.my;
00375 dict["apix_z"] = feimrch.zlen / feimrch.mz;
00376
00377 dict["FEIMRC.next"] = feimrch.next;
00378 dict["FEIMRC.dvid"] = feimrch.dvid;
00379 dict["FEIMRC.numintegers"] = feimrch.numintegers;
00380 dict["FEIMRC.numfloats"] = feimrch.numfloats;
00381 dict["FEIMRC.sub"] = feimrch.sub;
00382 dict["FEIMRC.zfac"] = feimrch.zfac;
00383
00384 dict["FEIMRC.min2"] = feimrch.min2;
00385 dict["FEIMRC.max2"] = feimrch.max2;
00386 dict["FEIMRC.min3"] = feimrch.min3;
00387 dict["FEIMRC.max3"] = feimrch.max3;
00388 dict["FEIMRC.min4"] = feimrch.min4;
00389 dict["FEIMRC.max4"] = feimrch.max4;
00390
00391 dict["FEIMRC.idtype"] = feimrch.idtype;
00392 dict["FEIMRC.lens"] = feimrch.lens;
00393 dict["FEIMRC.nd1"] = feimrch.nd1;
00394 dict["FEIMRC.nd2"] = feimrch.nd2;
00395 dict["FEIMRC.vd1"] = feimrch.vd1;
00396 dict["FEIMRC.vd2"] = feimrch.vd2;
00397
00398 for(int i=0; i<9; i++) {
00399 char label[32];
00400 sprintf(label, "MRC.tiltangles%d", i);
00401 dict[string(label)] = feimrch.tiltangles[i];
00402 }
00403
00404 dict["FEIMRC.zorg"] = feimrch.zorg;
00405 dict["FEIMRC.xorg"] = feimrch.xorg;
00406 dict["FEIMRC.yorg"] = feimrch.yorg;
00407
00408 dict["FEIMRC.nlabl"] = feimrch.nlabl;
00409 for (int i = 0; i < feimrch.nlabl; i++) {
00410 char label[32];
00411 sprintf(label, "MRC.label%d", i);
00412 dict[string(label)] = string(feimrch.labl[i], 80);
00413 }
00414
00415
00416 FeiMrcExtHeader feiexth;
00417 portable_fseek(mrcfile, sizeof(FeiMrcHeader)+sizeof(FeiMrcExtHeader)*image_index, SEEK_SET);
00418 if (fread(&feiexth, sizeof(FeiMrcExtHeader), 1, mrcfile) != 1) {
00419 throw ImageReadException(filename, "FEI MRC extended header");
00420 }
00421
00422 dict["FEIMRC.a_tilt"] = feiexth.a_tilt;
00423 dict["FEIMRC.b_tilt"] = feiexth.b_tilt;
00424
00425 dict["FEIMRC.x_stage"] = feiexth.x_stage;
00426 dict["FEIMRC.y_stage"] = feiexth.y_stage;
00427 dict["FEIMRC.z_stage"] = feiexth.z_stage;
00428
00429 dict["FEIMRC.x_shift"] = feiexth.x_shift;
00430 dict["FEIMRC.y_shift"] = feiexth.y_shift;
00431
00432 dict["FEIMRC.defocus"] = feiexth.defocus;
00433 dict["FEIMRC.exp_time"] = feiexth.exp_time;
00434 dict["FEIMRC.mean_int"] = feiexth.mean_int;
00435 dict["FEIMRC.tilt_axis"] = feiexth.tilt_axis;
00436
00437 dict["FEIMRC.pixel_size"] = feiexth.pixel_size;
00438 dict["FEIMRC.magnification"] = feiexth.magnification;
00439 dict["FEIMRC.ht"] = feiexth.ht;
00440 dict["FEIMRC.binning"] = feiexth.binning;
00441 dict["FEIMRC.appliedDefocus"] = feiexth.appliedDefocus;
00442
00443
00444
00445 EXITFUNC;
00446 return 0;
00447 }
00448
00449 int MrcIO::write_header(const Dict & dict, int image_index, const Region* area,
00450 EMUtil::EMDataType filestoragetype, bool use_host_endian)
00451 {
00452 ENTERFUNC;
00453
00454
00455 if(image_index == -1) {
00456 image_index = 0;
00457 }
00458 if(image_index != 0) {
00459 throw ImageWriteException(filename, "MRC file does not support stack.");
00460 }
00461 check_write_access(rw_mode, image_index, 1);
00462 if (area) {
00463 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00464 EXITFUNC;
00465 return 0;
00466 }
00467
00468 int new_mode = to_mrcmode(filestoragetype, (int) dict["is_complex"]);
00469 int nx = dict["nx"];
00470 int ny = dict["ny"];
00471 int nz = dict["nz"];
00472 is_ri = dict["is_complex_ri"];
00473
00474 bool opposite_endian = false;
00475
00476 if (!is_new_file) {
00477 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00478 opposite_endian = true;
00479 }
00480 #if 0
00481 if (new_mode != mrch.mode) {
00482 LOGERR("cannot write to different mode file %s", filename.c_str());
00483 return 1;
00484 }
00485 #endif
00486 portable_fseek(mrcfile, 0, SEEK_SET);
00487 }
00488 else {
00489 mrch.alpha = mrch.beta = mrch.gamma = 90.0f;
00490 mrch.mapc = 1;
00491 mrch.mapr = 2;
00492 mrch.maps = 3;
00493 mrch.nxstart = mrch.nystart = mrch.nzstart = 0;
00494 }
00495
00496 if(nz<=1 && dict.has_key("xform.projection") && !dict.has_key("UCSF.chimera")) {
00497 Transform * t = dict["xform.projection"];
00498 Dict d = t->get_params("imagic");
00499 mrch.alpha = d["alpha"];
00500 mrch.beta = d["beta"];
00501 mrch.gamma = d["gamma"];
00502 mrch.xorigin = d["tx"];
00503 mrch.yorigin = d["ty"];
00504 mrch.zorigin = d["tz"];
00505 if(t) {delete t; t=0;}
00506 }
00507 else if(nz>1 && dict.has_key("xform.align3d") && !dict.has_key("UCSF.chimera")) {
00508 Transform * t = dict["xform.align3d"];
00509 Dict d = t->get_params("imagic");
00510 mrch.alpha = d["alpha"];
00511 mrch.beta = d["beta"];
00512 mrch.gamma = d["gamma"];
00513 mrch.xorigin = d["tx"];
00514 mrch.yorigin = d["ty"];
00515 mrch.zorigin = d["tz"];
00516 if(t) {delete t; t=0;}
00517 }
00518
00519 if(dict.has_key("origin_x") && dict.has_key("origin_y") && dict.has_key("origin_z")){
00520 mrch.xorigin = (float)dict["origin_x"];
00521 mrch.yorigin = (float)dict["origin_y"];
00522
00523 if (is_new_file) {
00524 mrch.zorigin = (float)dict["origin_z"];
00525 }
00526 else {
00527 mrch.zorigin = (float) dict["origin_z"] - (float) dict["apix_z"] * image_index;
00528 }
00529 }
00530
00531 if (dict.has_key("MRC.nlabels")) {
00532 mrch.nlabels = dict["MRC.nlabels"];
00533 }
00534
00535 for (int i = 0; i < MRC_NUM_LABELS; i++) {
00536 char label[32];
00537 sprintf(label, "MRC.label%d", i);
00538 if (dict.has_key(label)) {
00539 sprintf(&mrch.labels[i][0], "%s", (const char *) dict[label]);
00540 mrch.nlabels = i + 1;
00541 }
00542 }
00543
00544 if (mrch.nlabels < (MRC_NUM_LABELS - 1)) {
00545 sprintf(&mrch.labels[mrch.nlabels][0], "EMAN %s", Util::get_time_label().c_str());
00546 mrch.nlabels++;
00547 }
00548
00549 mrch.labels[mrch.nlabels][0] = '\0';
00550 mrch.mode = new_mode;
00551
00552 if (is_complex_mode()) {
00553 mrch.nx = nx / 2;
00554 }
00555 else {
00556 mrch.nx = nx;
00557 }
00558 mrch.ny = ny;
00559
00560 if (is_new_file) {
00561 mrch.nz = nz;
00562 }
00563 else if (image_index >= mrch.nz) {
00564 mrch.nz = image_index + 1;
00565 }
00566
00567 mrch.ispg = 0;
00568 mrch.nsymbt = 0;
00569 mrch.amin = dict["minimum"];
00570 mrch.amax = dict["maximum"];
00571 mrch.amean = dict["mean"];
00572 mrch.rms = dict["sigma"];
00573
00576
00577
00578
00579
00580 mrch.mx = nx;
00581
00582
00583
00584
00585
00586 mrch.my = ny;
00587
00588
00589
00590
00591
00592 mrch.mz = nz;
00593
00594
00595 mrch.xlen = mrch.mx * (float) dict["apix_x"];
00596 mrch.ylen = mrch.my * (float) dict["apix_y"];
00597 mrch.zlen = mrch.mz * (float) dict["apix_z"];
00598
00599 if(dict.has_key("MRC.nxstart")) {
00600 mrch.nxstart = dict["MRC.nxstart"];
00601 }
00602 else {
00603 mrch.nxstart = -nx / 2;
00604 }
00605 if(dict.has_key("MRC.nystart")) {
00606 mrch.nystart = dict["MRC.nystart"];
00607 }
00608 else {
00609 mrch.nystart = -ny / 2;
00610 }
00611 if(dict.has_key("MRC.nzstart")) {
00612 mrch.nzstart = dict["MRC.nzstart"];
00613 }
00614 else {
00615 mrch.nzstart = -nz / 2;
00616 }
00617
00618 sprintf(mrch.map, "MAP ");
00619 mrch.machinestamp = generate_machine_stamp();
00620
00621 MrcHeader mrch2 = mrch;
00622
00623 if (opposite_endian || !use_host_endian) {
00624 swap_header(mrch2);
00625 }
00626
00627 if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
00628 throw ImageWriteException(filename, "MRC header");
00629 }
00630
00631 mode_size = get_mode_size(mrch.mode);
00632 is_new_file = false;
00633
00634 if( dict.has_key("ctf") ) {
00635 vector<float> vctf = dict["ctf"];
00636 EMAN1Ctf ctf_;
00637 ctf_.from_vector(vctf);
00638 write_ctf(ctf_);
00639 }
00640
00641 EXITFUNC;
00642 return 0;
00643 }
00644
00645 int MrcIO::read_data(float *rdata, int image_index, const Region * area, bool )
00646 {
00647 ENTERFUNC;
00648
00649 if(!isFEI) {
00650
00651 image_index = 0;
00652 }
00653
00654 check_read_access(image_index, rdata);
00655
00656 if (area && is_complex_mode()) {
00657 LOGERR("Error: cannot read a region of a complex image.");
00658 return 1;
00659 }
00660
00661 unsigned char *cdata = (unsigned char *) rdata;
00662 short *sdata = (short *) rdata;
00663 unsigned short *usdata = (unsigned short *) rdata;
00664
00665 size_t size = 0;
00666 int xlen = 0, ylen = 0, zlen = 0;
00667 if(isFEI) {
00668 check_region(area, FloatSize(mrch.nx, mrch.ny, 1), is_new_file, false);
00669 portable_fseek(mrcfile, sizeof(MrcHeader)+feimrch.next, SEEK_SET);
00670
00671 Region * new_area;
00672 if(area) {
00673 new_area = new Region(area->x_origin(), area->y_origin(), (float)image_index, area->get_width(), area->get_height(), 1.0f);
00674 }
00675 else {
00676 new_area = new Region(0, 0, image_index, feimrch.nx, feimrch.ny, 1);
00677 }
00678 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00679 image_index, mode_size,
00680 feimrch.nx, feimrch.ny, feimrch.nz, new_area);
00681
00682 EMUtil::get_region_dims(new_area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00683
00684 size = xlen * ylen * zlen;
00685
00686 delete new_area;
00687 }
00688 else {
00689 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file, false);
00690 portable_fseek(mrcfile, sizeof(MrcHeader)+mrch.nsymbt, SEEK_SET);
00691
00692 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00693 image_index, mode_size,
00694 mrch.nx, mrch.ny, mrch.nz, area);
00695
00696 EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00697
00698 size = xlen * ylen * zlen;
00699 }
00700
00701 if (mrch.mode != MRC_UCHAR) {
00702 if (mode_size == sizeof(short)) {
00703 become_host_endian < short >(sdata, size);
00704 }
00705 else if (mode_size == sizeof(float)) {
00706 become_host_endian < float >(rdata, size);
00707 }
00708 }
00709
00710 if (mrch.mode == MRC_UCHAR) {
00711 for (size_t i = 0; i < size; ++i) {
00712 size_t j = size - 1 - i;
00713
00714 rdata[j] = static_cast < float >(cdata[j]);
00715 }
00716 }
00717 else if (mrch.mode == MRC_SHORT ) {
00718 for (size_t i = 0; i < size; ++i) {
00719 size_t j = size - 1 - i;
00720 rdata[j] = static_cast < float >(sdata[j]);
00721 }
00722 }
00723 else if (mrch.mode == MRC_USHORT) {
00724 for (size_t i = 0; i < size; ++i) {
00725 size_t j = size - 1 - i;
00726 rdata[j] = static_cast < float >(usdata[j]);
00727 }
00728 }
00729
00730 if (is_complex_mode()) {
00731 if(!is_ri) Util::ap2ri(rdata, size);
00732 Util::flip_complex_phase(rdata, size);
00733 Util::rotate_phase_origin(rdata, xlen, ylen, zlen);
00734 }
00735 EXITFUNC;
00736 return 0;
00737 }
00738
00739 int MrcIO::write_data(float *data, int image_index, const Region* area,
00740 EMUtil::EMDataType, bool use_host_endian)
00741 {
00742 ENTERFUNC;
00743
00744 image_index = 0;
00745 check_write_access(rw_mode, image_index, 1, data);
00746 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00747
00748 int nx = mrch.nx;
00749 int ny = mrch.ny;
00750 int nz = mrch.nz;
00751 size_t size = (size_t)nx * ny * nz;
00752
00753 if (is_complex_mode()) {
00754 nx *= 2;
00755 if (!is_ri) {
00756 Util::ap2ri(data, size);
00757 is_ri = 1;
00758 }
00759 Util::flip_complex_phase(data, size);
00760 Util::rotate_phase_origin(data, nx, ny, nz);
00761 }
00762
00763 portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
00764
00765 if ( (is_big_endian != ByteOrder::is_host_big_endian()) || !use_host_endian) {
00766 if (mrch.mode != MRC_UCHAR) {
00767 if (mode_size == sizeof(short)) {
00768 ByteOrder::swap_bytes((short*) data, size);
00769 }
00770 else if (mode_size == sizeof(float)) {
00771 ByteOrder::swap_bytes((float*) data, size);
00772 }
00773 }
00774 }
00775 mode_size = get_mode_size(mrch.mode);
00776
00777
00778
00779
00780 void * ptr_data = data;
00781
00782 float rendermin = 0.0f;
00783 float rendermax = 0.0f;
00784 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, nz);
00785
00786 unsigned char *cdata = 0;
00787 short *sdata = 0;
00788 unsigned short *usdata = 0;
00789 if (mrch.mode == MRC_UCHAR) {
00790 cdata = new unsigned char[size];
00791 for (size_t i = 0; i < size; ++i) {
00792 if(data[i] <= rendermin) {
00793 cdata[i] = 0;
00794 }
00795 else if(data[i] >= rendermax){
00796 cdata[i] = UCHAR_MAX;
00797 }
00798 else {
00799 cdata[i]=(unsigned char)((data[i]-rendermin)/(rendermax-rendermin)*UCHAR_MAX);
00800 }
00801 }
00802 ptr_data = cdata;
00803 update_stat((void *)cdata);
00804 }
00805 else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00806 sdata = new short[size];
00807 for (size_t i = 0; i < size; ++i) {
00808 if(data[i] <= rendermin) {
00809 sdata[i] = SHRT_MIN;
00810 }
00811 else if(data[i] >= rendermax) {
00812 sdata[i] = SHRT_MAX;
00813 }
00814 else {
00815 sdata[i]=(short)(((data[i]-rendermin)/(rendermax-rendermin))*(SHRT_MAX-SHRT_MIN) - SHRT_MAX);
00816 }
00817 }
00818 ptr_data = sdata;
00819 update_stat((void *)sdata);
00820 }
00821 else if (mrch.mode == MRC_USHORT) {
00822 usdata = new unsigned short[size];
00823 for (size_t i = 0; i < size; ++i) {
00824 if(data[i] <= rendermin) {
00825 usdata[i] = 0;
00826 }
00827 else if(data[i] >= rendermax) {
00828 usdata[i] = USHRT_MAX;
00829 }
00830 else {
00831 usdata[i]=(unsigned short)((data[i]-rendermin)/(rendermax-rendermin)*USHRT_MAX);
00832 }
00833 }
00834 ptr_data = usdata;
00835 update_stat((void *)usdata);
00836 }
00837
00838
00839
00840
00841 EMUtil::process_region_io(ptr_data, mrcfile, WRITE_ONLY, image_index,
00842 mode_size, nx, mrch.ny, mrch.nz, area);
00843
00844 if(cdata) {delete [] cdata; cdata=0;}
00845 if(sdata) {delete [] sdata; sdata=0;}
00846 if(usdata) {delete [] usdata; usdata=0;}
00847
00848 #if 0
00849 int row_size = nx * get_mode_size(mrch.mode);
00850 int sec_size = nx * ny;
00851
00852 unsigned char *cbuf = new unsigned char[row_size];
00853 unsigned short *sbuf = (unsigned short *) cbuf;
00854
00855 for (int i = 0; i < nz; i++) {
00856 int i2 = i * sec_size;
00857 for (int j = 0; j < ny; j++) {
00858 int k = i2 + j * nx;
00859 void *pbuf = 0;
00860
00861 switch (mrch.mode) {
00862 case MRC_UCHAR:
00863 for (int l = 0; l < nx; l++) {
00864 cbuf[l] = static_cast < unsigned char >(data[k + l]);
00865 }
00866 pbuf = cbuf;
00867 fwrite(cbuf, row_size, 1, mrcfile);
00868 break;
00869
00870 case MRC_SHORT:
00871 case MRC_SHORT_COMPLEX:
00872 for (int l = 0; l < nx; l++) {
00873 sbuf[l] = static_cast < short >(data[k + l]);
00874 }
00875 pbuf = sbuf;
00876 fwrite(sbuf, row_size, 1, mrcfile);
00877 break;
00878
00879 case MRC_USHORT:
00880 for (int l = 0; l < nx; l++) {
00881 sbuf[l] = static_cast < unsigned short >(data[k + l]);
00882 }
00883 pbuf = sbuf;
00884 fwrite(sbuf, row_size, 1, mrcfile);
00885 break;
00886
00887 case MRC_FLOAT:
00888 case MRC_FLOAT_COMPLEX:
00889 pbuf = &data[k];
00890 break;
00891 }
00892 if (pbuf) {
00893 fwrite(pbuf, row_size, 1, mrcfile);
00894 }
00895 }
00896 }
00897
00898 if(cbuf)
00899 {
00900 delete[]cbuf;
00901 cbuf = 0;
00902 }
00903 #endif
00904
00905 EXITFUNC;
00906 return 0;
00907 }
00908
00909 void MrcIO::update_stat(void* data)
00910 {
00911 size_t size = mrch.nx * mrch.ny * mrch.nz;
00912 float v = 0.0f;
00913 double sum = 0.0;
00914 double square_sum = 0.0;
00915 double mean = 0.0;
00916 float min, max;
00917
00918 unsigned char * cdata = 0;
00919 short * sdata = 0;
00920 unsigned short * usdata = 0;
00921
00922 if (mrch.mode == MRC_UCHAR) {
00923 max = 0.0f;
00924 min = UCHAR_MAX;
00925 cdata = (unsigned char *)data;
00926
00927 for (size_t i = 0; i < size; ++i) {
00928 v = (float)(cdata[i]);
00929 #ifdef _WIN32
00930 max = _cpp_max(max,v);
00931 min = _cpp_min(min,v);
00932 #else
00933 max=std::max<float>(max,v);
00934 min=std::min<float>(min,v);
00935 #endif //_WIN32
00936
00937 sum += v;
00938 square_sum += v * v;
00939 }
00940 }
00941 else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00942 max = (float)SHRT_MIN;
00943 min = (float)SHRT_MAX;
00944 sdata = (short *)data;
00945
00946 for (size_t i = 0; i < size; ++i) {
00947 v = (float)(sdata[i]);
00948 #ifdef _WIN32
00949 max = _cpp_max(max,v);
00950 min = _cpp_min(min,v);
00951 #else
00952 max=std::max<float>(max,v);
00953 min=std::min<float>(min,v);
00954 #endif //_WIN32
00955
00956 sum += v;
00957 square_sum += v * v;
00958 }
00959 }
00960 else if (mrch.mode == MRC_USHORT) {
00961 max = 0.0f;
00962 min = (float)USHRT_MAX;
00963 usdata = (unsigned short*)data;
00964
00965 for (size_t i = 0; i < size; ++i) {
00966 v = (float)(usdata[i]);
00967 #ifdef _WIN32
00968 max = _cpp_max(max,v);
00969 min = _cpp_min(min,v);
00970 #else
00971 max=std::max<float>(max,v);
00972 min=std::min<float>(min,v);
00973 #endif //_WIN32
00974
00975 sum += v;
00976 square_sum += v * v;
00977 }
00978 }
00979 else {
00980 throw InvalidCallException("This function is used to write 8bit/16bit mrc file only.");
00981 }
00982
00983 mean = sum/size;
00984 #ifdef _WIN32
00985 float sigma = (float)std::sqrt( _cpp_max(0.0,(square_sum - sum*sum / size)/(size-1)));
00986 #else
00987 float sigma = (float)std::sqrt(std::max<float>(0.0,(square_sum - sum*sum / size)/(size-1)));
00988 #endif //_WIN32
00989
00990
00991 mrch.amin = min;
00992 mrch.amax = max;
00993 mrch.amean = (float)mean;
00994 mrch.rms = sigma;
00995
00996 MrcHeader mrch2 = mrch;
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 portable_fseek(mrcfile, 0, SEEK_SET);
01014
01015 if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
01016 throw ImageWriteException(filename, "MRC header");
01017 }
01018
01019 portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
01020 }
01021
01022 bool MrcIO::is_complex_mode()
01023 {
01024 init();
01025 if (mrch.mode == MRC_SHORT_COMPLEX || mrch.mode == MRC_FLOAT_COMPLEX) {
01026 return true;
01027 }
01028 return false;
01029 }
01030
01031
01032 int MrcIO::read_ctf(Ctf & ctf, int)
01033 {
01034 ENTERFUNC;
01035 init();
01036 size_t n = strlen(CTF_MAGIC);
01037
01038 int err = 1;
01039 if (strncmp(&mrch.labels[0][0], CTF_MAGIC, n) == 0) {
01040 err = ctf.from_string(string(&mrch.labels[0][n]));
01041 }
01042 EXITFUNC;
01043 return err;
01044 }
01045
01046 void MrcIO::write_ctf(const Ctf & ctf, int)
01047 {
01048 ENTERFUNC;
01049 init();
01050
01051 string ctf_str = ctf.to_string();
01052 sprintf(&mrch.labels[0][0], "%s%s", CTF_MAGIC, ctf_str.c_str());
01053 rewind(mrcfile);
01054
01055 if (fwrite(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
01056 throw ImageWriteException(filename, "write CTF info to header failed");
01057 }
01058 EXITFUNC;
01059 }
01060
01061 void MrcIO::flush()
01062 {
01063 fflush(mrcfile);
01064 }
01065
01066
01067 int MrcIO::get_mode_size(int mm)
01068 {
01069 MrcIO::MrcMode m = static_cast < MrcMode > (mm);
01070
01071 int msize = 0;
01072 switch (m) {
01073 case MRC_UCHAR:
01074 msize = sizeof(char);
01075 break;
01076 case MRC_SHORT:
01077 case MRC_USHORT:
01078 case MRC_SHORT_COMPLEX:
01079 msize = sizeof(short);
01080 break;
01081 case MRC_FLOAT:
01082 case MRC_FLOAT_COMPLEX:
01083 msize = sizeof(float);
01084 break;
01085 default:
01086 msize = 0;
01087 }
01088
01089 return msize;
01090 }
01091
01092 int MrcIO::to_em_datatype(int m)
01093 {
01094 EMUtil::EMDataType e = EMUtil::EM_UNKNOWN;
01095
01096 switch (m) {
01097 case MRC_UCHAR:
01098 e = EMUtil::EM_UCHAR;
01099 break;
01100 case MRC_SHORT:
01101 e = EMUtil::EM_SHORT;
01102 break;
01103 case MRC_USHORT:
01104 e = EMUtil::EM_USHORT;
01105 break;
01106 case MRC_SHORT_COMPLEX:
01107 e = EMUtil::EM_SHORT_COMPLEX;
01108 break;
01109 case MRC_FLOAT:
01110 e = EMUtil::EM_FLOAT;
01111 break;
01112 case MRC_FLOAT_COMPLEX:
01113 e = EMUtil::EM_FLOAT_COMPLEX;
01114 break;
01115 default:
01116 e = EMUtil::EM_UNKNOWN;
01117 }
01118 return e;
01119 }
01120
01121
01122 int MrcIO::to_mrcmode(int e, int is_complex)
01123 {
01124 MrcMode m = MRC_UNKNOWN;
01125 EMUtil::EMDataType em_type = static_cast < EMUtil::EMDataType > (e);
01126
01127 switch (em_type) {
01128 case EMUtil::EM_UCHAR:
01129 m = MRC_UCHAR;
01130 break;
01131 case EMUtil::EM_USHORT:
01132 if (is_complex) {
01133 m = MRC_SHORT_COMPLEX;
01134 }
01135 else {
01136 m = MRC_USHORT;
01137 }
01138 break;
01139 case EMUtil::EM_SHORT:
01140 if (is_complex) {
01141 m = MRC_SHORT_COMPLEX;
01142 }
01143 else {
01144 m = MRC_SHORT;
01145 }
01146 break;
01147 case EMUtil::EM_SHORT_COMPLEX:
01148 case EMUtil::EM_USHORT_COMPLEX:
01149 m = MRC_SHORT_COMPLEX;
01150 break;
01151 case EMUtil::EM_CHAR:
01152 case EMUtil::EM_INT:
01153 case EMUtil::EM_UINT:
01154 case EMUtil::EM_FLOAT:
01155 if (is_complex) {
01156 m = MRC_FLOAT_COMPLEX;
01157 }
01158 else {
01159 m = MRC_FLOAT;
01160 }
01161 break;
01162 case EMUtil::EM_FLOAT_COMPLEX:
01163 m = MRC_FLOAT_COMPLEX;
01164 break;
01165 default:
01166 m = MRC_FLOAT;
01167 }
01168
01169 return m;
01170 }
01171
01172
01173
01174 int MrcIO::generate_machine_stamp()
01175 {
01176 int stamp = 0;
01177 char *p = (char *) (&stamp);
01178
01179 if (ByteOrder::is_host_big_endian()) {
01180 p[0] = 0x11;
01181 p[1] = 0x11;
01182 p[2] = 0;
01183 p[3] = 0;
01184 }
01185 else {
01186 p[0] = 0x44;
01187 p[1] = 0x41;
01188 p[2] = 0;
01189 p[3] = 0;
01190 }
01191 return stamp;
01192 }
01193
01194 void MrcIO::swap_header(MrcHeader& mrch)
01195 {
01196 ByteOrder::swap_bytes((int *) &mrch, NUM_4BYTES_PRE_MAP);
01197 ByteOrder::swap_bytes((int *) &mrch.machinestamp, NUM_4BYTES_AFTER_MAP);
01198 }
01199
01200 int MrcIO::get_nimg()
01201 {
01202 init();
01203
01204 if(isFEI) {
01205 return feimrch.nz;
01206 }
01207 else {
01208 return 1;
01209 }
01210 }