找回密码
 立即注册
搜索
查看: 462|回复: 14

[耍宝娱乐] TC低菊渲染(污染)实验贴

[复制链接]

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
发表于 2026-2-20 21:05 | 显示全部楼层 |阅读模式
自制了一个程序,从MODIS的L1B存档读取数据,并且渲染成一些特定色阶。
十分低菊,希望大家能够给出建议,共同进步
如果遇到认为观感猎奇的图片,可以在下方发表情或者与其他8u分享
以下的代码应该会发布,找不到了的就不发了
Megi全IR镇楼

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-20 21:07 | 显示全部楼层
代码:
  1. #include <algorithm>
  2. #include <chrono>
  3. #include <cmath>
  4. #include <complex>
  5. #include <cpgplot.h>
  6. #include <iostream>
  7. #include <limits>
  8. #include <map>
  9. #include <mfhdf.h>
  10. #include <numbers>
  11. #include <stdexcept>
  12. #include <type_traits>
  13. #include <vector>

  14. #define PNG_OUTPUT

  15. constexpr double Hc_k = 1.4387768775039337e4;
  16. constexpr double H2c_2 = 1.1910429723971884140794892e8;
  17. constexpr double Deg2rad = std::numbers::pi / 180;
  18. constexpr double K2c = -273.15;
  19. static float low = -90, high = 33;
  20. static int lowcol = 0, hicol = 16;

  21. constexpr double brtemp(double bt, double lam_um) {
  22.         return Hc_k / lam_um / std::log(H2c_2 / pow(lam_um, 5) / bt + 1);
  23. }

  24. int color_brtemp(double brtempC) {
  25.         double zonnap = std::clamp((brtempC - low) / (high - low), 0., 1.);
  26.         int mincol, maxcol;
  27.         cpgqcir(&mincol, &maxcol);
  28.         return mincol + (maxcol - mincol) * zonnap;
  29. }

  30. void set_color() {
  31.         cpgscr(16, 0.5, 0.5, 0.75);
  32.         cpgscr(15, 0.4, 0.4, 0.6);
  33.         cpgscr(14, 0.3, 0.3, 0.45);
  34.         cpgscr(13, 0.2, 0.2, 0.3);
  35.         cpgscr(12, 0.1, 0.1, 0.15);
  36. }

  37. template<int32 Nt>
  38. using SDtype =
  39.         std::conditional_t<Nt == 3, int8,
  40.         std::conditional_t<Nt == 4, char8,
  41.         std::conditional_t<Nt == 5, float32,
  42.         std::conditional_t<Nt == 6, float64,
  43.         std::conditional_t<Nt == 20, int8,
  44.         std::conditional_t<Nt == 21, uint8,
  45.         std::conditional_t<Nt == 22, int16,
  46.         std::conditional_t<Nt == 23, uint16,
  47.         std::conditional_t<Nt == 24, int32,
  48.         std::conditional_t<Nt == 25, uint32, void>>>>>>>>>>;

  49. struct SDfile {
  50.         int32 sdid;
  51.         int32 ndataset, nattr;
  52.         template<class Tp>
  53.         struct Attribute {
  54.                 int32 obj_id, index;
  55.                 int32 type, count;
  56.                 char name[256];
  57.                 std::vector<Tp> data;
  58.                 Attribute(int32 pobj_id, int32 pindex)
  59.                         :obj_id(pobj_id), index(pindex) {
  60.                         SDattrinfo(pobj_id, pindex, name, &type, &count);
  61.                         data.assign(count, Tp());
  62.                         SDreadattr(obj_id, index, data.data());
  63.                 }
  64.         };
  65.         struct SDS {
  66.                 int32 All_begin[MAX_VAR_DIMS]{};
  67.                 template<class Tp>
  68.                 struct Data_array {
  69.                         int32 dimn;
  70.                         int32 dims[MAX_VAR_DIMS];
  71.                         Tp* data;
  72.                         Tp operator[] (std::initializer_list<int32> dimensions) const {
  73.                                 auto it = dimensions.end();
  74.                                 size_t dimit = dimn - 1, pnow = 1, datanow = 0;
  75.                                 do
  76.                                 {
  77.                                         --it;
  78.                                         datanow += *it * pnow;
  79.                                         pnow *= dims[dimit--];
  80.                                 } while (it != dimensions.begin());
  81.                                 return data[datanow];
  82.                         }
  83.                         Data_array(const SDS* from_sds, const int32* vdims)
  84.                                 :dimn(from_sds->dimn) {
  85.                                 std::copy_n(vdims, from_sds->dimn, dims);
  86.                                 size_t tot = 1;
  87.                                 for (int i = 0; i < dimn; i++)
  88.                                         tot *= dims[i];
  89.                                 data = new Tp[tot];
  90.                         }
  91.                         ~Data_array() { delete[] data; }
  92.                 };
  93.                 int32 sdsid;
  94.                 char name[256];
  95.                 int32 dimn;
  96.                 int32 dims[MAX_VAR_DIMS];
  97.                 int32 dattype;
  98.                 int32 nattr;
  99.                 template<class Tp>
  100.                 Data_array<Tp> get() {
  101.                         Data_array<Tp> res(this, dims);
  102.                         SDreaddata(sdsid, All_begin, nullptr, dims, res.data);
  103.                         return res;
  104.                 }
  105.                 template<class Tp>
  106.                 Data_array<Tp> get(const std::vector<int32>& start, const std::vector<int32>& cntrd) {
  107.                         auto mvas = start, mvac = cntrd;
  108.                         Data_array<Tp> res(this, cntrd.data());
  109.                         SDreaddata(sdsid, mvas.data(), nullptr, mvac.data(), res.data);
  110.                         return res;
  111.                 }
  112.                 template<class Tp>
  113.                 Attribute<Tp> attribute(int32 attr_index) {
  114.                         return Attribute<Tp>(sdsid, attr_index);
  115.                 }
  116.                 template<class Tp>
  117.                 Attribute<Tp> attribute(std::string_view attrname) {
  118.                         return Attribute<Tp>(sdsid, SDfindattr(sdsid, attrname.data()));
  119.                 }
  120.                 SDS(int sds_id)
  121.                         :sdsid(sds_id) {
  122.                         SDgetinfo(sds_id, name, &dimn, dims, &dattype, &nattr);
  123.                 }
  124.                 ~SDS() { SDendaccess(sdsid); }
  125.         };
  126.         SDS select(int32 index) {
  127.                 return SDS(SDselect(sdid, index));
  128.         }
  129.         SDS select(std::string_view sdsname) {
  130.                 return SDS(SDselect(sdid, SDnametoindex(sdid, sdsname.data())));
  131.         }
  132.         template<class Tp>
  133.                 Attribute<Tp> attribute(int32 attr_index) {
  134.                 return Attribute<Tp>(sdid, attr_index);
  135.         }
  136.         template<class Tp>
  137.         Attribute<Tp> attribute(std::string_view attrname) {
  138.                 return Attribute<Tp>(sdid, SDfindattr(sdid, attrname.data()));
  139.         }
  140.         SDfile(std::string_view filename)
  141.                 :sdid(SDstart(filename.data(), DFACC_READ)) {
  142.                 SDfileinfo(sdid, &ndataset, &nattr);
  143.         }
  144.         ~SDfile() { SDend(sdid); }
  145. };

  146. std::map<std::string, double> Center_Wl_in_um{
  147.         {"1", (0.62 + 0.67) / 2},
  148.         {"2", (0.841 + 0.876) / 2},
  149.         {"3", (0.459 + 0.479) / 2},
  150.         {"4", (0.545 + 0.565) / 2},
  151.         {"5", (1.23 + 1.25) / 2},
  152.         {"6", (1.628 + 1.652) / 2},
  153.         {"7", (2.105 + 2.155) / 2},
  154.         {"8", (0.405 + 0.42) / 2},
  155.         {"9", (0.438 + 0.448) / 2},
  156.         {"10", (0.483 + 0.493) / 2},
  157.         {"11", (0.526 + 0.536) / 2},
  158.         {"12", (0.546 + 0.556) / 2},
  159.         {"13hi", (0.662 + 0.672) / 2},
  160.         {"13lo", (0.662 + 0.672) / 2},
  161.         {"14hi", (0.673 + 0.683) / 2},
  162.         {"14lo", (0.673 + 0.683) / 2},
  163.         {"15", (0.743 + 0.753) / 2},
  164.         {"16", (0.862 + 0.877) / 2},
  165.         {"17", (0.89 + 0.92) / 2},
  166.         {"18", (0.931 + 0.941) / 2},
  167.         {"19", (0.915 + 0.965) / 2},
  168.         {"20", (3.66 + 3.84) / 2},
  169.         {"21", (3.929 + 3.989) / 2},
  170.         {"22", (3.929 + 3.989) / 2},
  171.         {"23", (4.02 + 4.08) / 2},
  172.         {"24", (4.433 + 4.498) / 2},
  173.         {"25", (4.482 + 4.549) / 2},
  174.         {"26", (1.36 + 1.39) / 2},
  175.         {"27", (6.535 + 6.895) / 2},
  176.         {"28", (7.175 + 7.475) / 2},
  177.         {"29", (8.4 + 8.7) / 2},
  178.         {"30", (9.58 + 9.88) / 2},
  179.         {"31", (10.78 + 11.28) / 2},
  180.         {"32", (11.77 + 12.27) / 2},
  181.         {"33", (13.185 + 13.485) / 2},
  182.         {"34", (13.485 + 13.785) / 2},
  183.         {"35", (13.785 + 14.085) / 2},
  184.         {"36", (14.085 + 14.385) / 2}
  185. };

  186. template<class Tp>
  187. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw);

  188. int main(int argc, char** argv) {
  189.         using namespace std;
  190.         if (argc < 2)
  191.                 throw invalid_argument("必须在 argv[1] 提供文件名");
  192.         auto lasttime = chrono::high_resolution_clock::now();
  193.         SDfile file(argv[1]);
  194.         /*
  195.          Latitude,Longitude,EV_1KM_RefSB,EV_1KM_RefSB_Uncert_Indexes,EV_1KM_Emissive,
  196.          EV_1KM_Emissive_Uncert_Indexes,EV_250_Aggr1km_RefSB,EV_250_Aggr1km_RefSB_Uncert_Indexes,
  197.          EV_250_Aggr1km_RefSB_Samples_Used,EV_500_Aggr1km_RefSB,EV_500_Aggr1km_RefSB_Uncert_Indexes,
  198.          EV_500_Aggr1km_RefSB_Samples_Used,Height,SensorZenith,SensorAzimuth,
  199.          Range,SolarZenith,SolarAzimuth,gflags,EV_Band26,EV_Band26_Uncert_Indexes,Band_250M,
  200.          Band_500M,Band_1KM_RefSB,Band_1KM_Emissive,Noise in Thermal Detectors,
  201.          Change in relative responses of thermal detectors,DC Restore Change for Thermal Bands,
  202.          DC Restore Change for Reflective 250m Bands,DC Restore Change for Reflective 500m Bands,
  203.          DC Restore Change for Reflective 1km Bands
  204.         */
  205.         string main_sdsname = "EV_1KM_Emissive";
  206.         auto sds = file.select(main_sdsname);
  207.         auto fulldat = sds.get<uint16>();
  208.         auto getbandname = [&] (int bdid) {
  209.                 string bandname;
  210.                 auto bds = sds.attribute<char>("band_names");
  211.                 int cnt = 0;
  212.                 for (auto ch : bds.data)
  213.                         if (ch == ',')
  214.                         {
  215.                                 if (cnt == bdid)
  216.                                         break;
  217.                                 bandname.clear();
  218.                                 ++cnt;
  219.                         }
  220.                         else
  221.                                 bandname.push_back(ch);
  222.                 return bandname;
  223.         };
  224.         auto readband = [&] (int bdid) {
  225.                 auto emmmat = new float[sds.dims[1] * sds.dims[2]];
  226.                 string bandname = getbandname(bdid);
  227.                 float ro = sds.attribute<float>("radiance_offsets").data[bdid],
  228.                 rs = sds.attribute<float>("radiance_scales").data[bdid];
  229.                 for (int i = 0; i < sds.dims[1]; i++)
  230.                         for (int j = 0; j < sds.dims[2]; j++)
  231.                                 emmmat[i * sds.dims[2] + j] = (fulldat[{bdid, i, j}] - ro) * rs;
  232.                 for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  233.                         emmmat[i] = brtemp(emmmat[i], Center_Wl_in_um.at(bandname));
  234.                 return emmmat;
  235.         };
  236.         int bdid = 11;
  237.         string lbinfo = main_sdsname + " Band\\d" + getbandname(bdid) + "\\u " +
  238.                 to_string(Center_Wl_in_um.at(getbandname(bdid))) + "um";
  239.         auto emmmat = readband(bdid);
  240.         string outname = string("'") + argv[1] + "-";
  241.         for (auto ch : lbinfo)
  242.                 if (ch == ' ')
  243.                         outname.push_back('-');
  244.                 else if (ch != '\\')
  245.                         outname.push_back(ch);
  246.         outname += ".png'";
  247.         auto solarzsds = file.select("SolarZenith");
  248.         auto solarzl0 = solarzsds.get<int16>();
  249.         SDfile::SDS::Data_array<float> solarzl1(&solarzsds, solarzsds.dims);
  250.         for (int i = 0; i < solarzl0.dims[0] * solarzl0.dims[1]; i++)
  251.                 solarzl1.data[i] = solarzl0.data[i] / 1e2;
  252.         auto solarzl2 = interp<float>(solarzl1, sds.dims[1], sds.dims[2]);
  253.         auto latsds = file.select("Latitude");
  254.         auto latl1 = latsds.get<float>();
  255.         auto latl2 = interp<float>(latl1, sds.dims[1], sds.dims[2]);
  256.         auto lonsds = file.select("Longitude");
  257.         auto lonl1 = lonsds.get<float>();
  258.         for (int i = 0; i < lonl1.dims[0] * lonl1.dims[1]; i++)
  259.                 if (lonl1.data[i] < 0)
  260.                         lonl1.data[i] += 360;
  261.         auto lonl2 = interp<float>(lonl1, sds.dims[1], sds.dims[2]);
  262.         cout << "读取数据用时: " <<
  263.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  264.                         - lasttime).count() / 1e6 << " s\n";
  265.         lasttime = chrono::high_resolution_clock::now();
  266. #ifdef PNG_OUTPUT
  267.         if (cpgopen("tmp.ps/VCPS") < 0)
  268. #else
  269.         if (cpgopen("/XWINDOW") < 0)
  270. #endif
  271.                 throw runtime_error("打开PGPLOT设备错误");
  272.         cpgbbuf();
  273.         auto tmp = file.attribute<char>("CoreMetadata.0").data;
  274.         string coremeta(tmp.begin(), tmp.end());
  275.         auto getcmt = [&] (string obj) {
  276.                 auto posm = coremeta.find("OBJECT                 = " + obj);
  277.                 auto pos = coremeta.find("VALUE                = ", posm);
  278.                 int offset = 23, backoff = 0;
  279.                 if (coremeta[pos + offset] == '"')
  280.                 {
  281.                         ++offset;
  282.                         ++backoff;
  283.                 }
  284.                 auto end = coremeta.find('\n', pos + offset);
  285.                 return coremeta.substr(pos + offset, end - pos - offset - backoff);
  286.         };
  287.         string device = getcmt("ASSOCIATEDSENSORSHORTNAME") + "/" +
  288.                 getcmt("ASSOCIATEDPLATFORMSHORTNAME");
  289.         string endtime = getcmt("RANGEENDINGDATE") + " " +
  290.                 getcmt("RANGEENDINGTIME");
  291.         while (endtime.back() == '0')
  292.                 endtime.pop_back();
  293.         endtime.pop_back();
  294.         endtime += "\\uUTC\\d";
  295.         auto latmmx =
  296.                 minmax_element(latl1.data, latl1.data + latl1.dims[0] * latl1.dims[1]),
  297.         lonmmx =
  298.                 minmax_element(lonl1.data, lonl1.data + lonl1.dims[0] * lonl1.dims[1]);
  299.         //cpgenv(*lonmmx.first, *lonmmx.second, *latmmx.first, *latmmx.second
  300.         //        , 1, 1);
  301.         cpgenv(122.5, 130, 15, 22, 1, 1);
  302.         cpglab("Lon", "Lat", argv[1]);
  303.         cpgmtxt("R", 1, 0, 0, lbinfo.c_str());
  304.         cpgmtxt("B", 2.5, 0.15, 0, device.c_str());
  305.         cpgmtxt("B", 2.5, 0.6, 0, endtime.c_str());
  306.         set_color();
  307.         cpgscir(lowcol, hicol);
  308.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  309.                 {
  310.                         if (isnan(emmmat[i]))
  311.                                 continue;
  312.                         int col = color_brtemp(emmmat[i] + K2c);
  313.                         int rind = i / sds.dims[2], cind = i % sds.dims[2];
  314.                         double colrng = (float)abs(cind - sds.dims[2] / 2) / sds.dims[2];
  315.                         double siz = 8e-3 * exp(3.5 * colrng + 0.8 * sqrt(abs(latl2[i]) * 1.3e-4)) +
  316.                                 4e-4 * exp(4 * pow(colrng, 2));
  317.                         cpgpixl(&col, 1, 1, 1, 1, 1, 1, lonl2[i],
  318.                                 lonl2[i] + siz, latl2[i], latl2[i] + siz);
  319.                 }
  320.         cpgwedg("RI", 2, 3, low, high, "^C");
  321.         cpgebuf();
  322.         cpgend();
  323.         cout << "PGPLOT输出用时: " <<
  324.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  325.                         - lasttime).count() / 1e6 << " s\n";
  326.         lasttime = chrono::high_resolution_clock::now();
  327. #ifdef PNG_OUTPUT
  328.         system(("magick -density 240 tmp.ps " + outname).c_str());
  329.         cout << "PNG转换用时: " <<
  330.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  331.                         - lasttime).count() / 1e6 << " s\n";
  332.         cout << "输出到PNG文件: " << outname << endl;
  333.         system("rm tmp.ps");
  334. #endif
  335.         delete[] solarzl2;
  336.         delete[] latl2;
  337.         delete[] lonl2;
  338.         delete[] emmmat;
  339.         return 0;
  340. }

  341. template<class Tp>
  342. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw) {
  343.         auto res = new Tp[dsth * dstw];
  344.         res[0] = init[{0, 0}];
  345.         res[dsth * dstw - 1] = init[{init.dims[0] - 1, init.dims[1] - 1}];
  346.         double deltaX = double(init.dims[0] - 1) / (dsth - 1), deltaY = double(init.dims[1] - 1) / (dstw - 1);
  347.         for (int i = 0; i < dsth; i++)
  348.                 for (int j = 0; j < dstw; j++)
  349.                         if ((i || j) && (i != dsth - 1 || j != dstw - 1))
  350.                         {
  351.                                 double mappedX = deltaX * i, mappedY = deltaY * j;
  352.                                 double cX = mappedX - floor(mappedX), cY = mappedY - floor(mappedY);
  353.                                 int x0 = mappedX, x1 = std::min<int>(ceil(mappedX), init.dims[0] - 1);
  354.                                 int y0 = mappedY, y1 = std::min<int>(ceil(mappedY), init.dims[1] - 1);
  355.                                 res[i * dstw + j] = (1 - cX) * (1 - cY) * init[{x0, y0}] +
  356.                                         (1 - cX) * cY * init[{x0, y1}] +
  357.                                                 cX * (1 - cY) * init[{x1, y0}] +
  358.                                                         cX * cY * init[{x1, y1}];
  359.                         }
  360.         return res;
  361. }
复制代码

运行环境需求:UNIX-Like系统(或许windows也可以)、imagemagick、Clang++/G++(未验证过)(支持C++17以上)、imagemagick、ghostscript、HDF4、cpgplot
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-20 21:17 | 显示全部楼层
另外一些TC和完整图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-21 08:28 | 显示全部楼层
B35距平,注意色阶不同


代码比较长,请改成cpp格式

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-21 08:30 | 显示全部楼层
wfIRstzhang 发表于 2026-2-21 08:28
B35距平,注意色阶不同

可以看到很明显的暖心
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-21 09:15 | 显示全部楼层
这些是B20距平,我是朵拉。帮我找找:
Patricia的外眼墙在哪里?
Melissa的重力波在哪里?
Co-may的低层环流中心在哪里?




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-22 08:34 | 显示全部楼层


  1. #include <algorithm>
  2. #include <chrono>
  3. #include <cmath>
  4. #include <complex>
  5. #include <cpgplot.h>
  6. #include <iostream>
  7. #include <limits>
  8. #include <map>
  9. #include <mfhdf.h>
  10. #include <numbers>
  11. #include <stdexcept>
  12. #include <type_traits>
  13. #include <vector>

  14. #define PNG_OUTPUT

  15. constexpr double Hc_k = 1.4387768775039337e4;
  16. constexpr double H2c_2 = 1.1910429723971884140794892e8;
  17. constexpr double Deg2rad = std::numbers::pi / 180;
  18. constexpr double K2c = -273.15;
  19. static float low = -40, high = 30;
  20. static int lowcol = 16, hicol = 254;

  21. constexpr double brtemp(double bt, double lam_um) {
  22.         return Hc_k / lam_um / std::log(H2c_2 / pow(lam_um, 5) / bt + 1);
  23. }

  24. int color_brtemp(double brtempC) {
  25.         double zonnap = std::clamp((brtempC - low) / (high - low), 0., 1.);
  26.         int mincol, maxcol;
  27.         cpgqcir(&mincol, &maxcol);
  28.         return mincol + (maxcol - mincol) * zonnap;
  29. }

  30. void set_color() {
  31.         // cpgscr(16, 0.5, 0.5, 0.75);
  32.         // cpgscr(15, 0.4, 0.4, 0.6);
  33.         // cpgscr(14, 0.3, 0.3, 0.45);
  34.         // cpgscr(13, 0.2, 0.2, 0.3);
  35.         // cpgscr(12, 0.1, 0.1, 0.15);
  36.         int midlen = (hicol - lowcol) / 2;
  37.         for (int i = lowcol; i <= lowcol + midlen; i++)
  38.         {
  39.                 float base = float(lowcol + midlen - i) / midlen;
  40.                 cpgscr(i, base, base, base);
  41.         }
  42.         for (int i = lowcol + midlen + 1; i <= lowcol + midlen * 2; i++)
  43.         {
  44.                 float base = float(i - lowcol - midlen) / midlen;
  45.                 cpgscr(i, base * 0.6, base * 0.6, base);
  46.         }
  47. }

  48. template<int32 Nt>
  49. using SDtype =
  50.         std::conditional_t<Nt == 3, int8,
  51.         std::conditional_t<Nt == 4, char8,
  52.         std::conditional_t<Nt == 5, float32,
  53.         std::conditional_t<Nt == 6, float64,
  54.         std::conditional_t<Nt == 20, int8,
  55.         std::conditional_t<Nt == 21, uint8,
  56.         std::conditional_t<Nt == 22, int16,
  57.         std::conditional_t<Nt == 23, uint16,
  58.         std::conditional_t<Nt == 24, int32,
  59.         std::conditional_t<Nt == 25, uint32, void>>>>>>>>>>;

  60. struct SDfile {
  61.         int32 sdid;
  62.         int32 ndataset, nattr;
  63.         template<class Tp>
  64.         struct Attribute {
  65.                 int32 obj_id, index;
  66.                 int32 type, count;
  67.                 char name[256];
  68.                 std::vector<Tp> data;
  69.                 Attribute(int32 pobj_id, int32 pindex)
  70.                         :obj_id(pobj_id), index(pindex) {
  71.                         SDattrinfo(pobj_id, pindex, name, &type, &count);
  72.                         data.assign(count, Tp());
  73.                         SDreadattr(obj_id, index, data.data());
  74.                 }
  75.         };
  76.         struct SDS {
  77.                 int32 All_begin[MAX_VAR_DIMS]{};
  78.                 template<class Tp>
  79.                 struct Data_array {
  80.                         int32 dimn;
  81.                         int32 dims[MAX_VAR_DIMS];
  82.                         Tp* data;
  83.                         Tp operator[] (std::initializer_list<int32> dimensions) const {
  84.                                 auto it = dimensions.end();
  85.                                 size_t dimit = dimn - 1, pnow = 1, datanow = 0;
  86.                                 do
  87.                                 {
  88.                                         --it;
  89.                                         datanow += *it * pnow;
  90.                                         pnow *= dims[dimit--];
  91.                                 } while (it != dimensions.begin());
  92.                                 return data[datanow];
  93.                         }
  94.                         Data_array(const SDS* from_sds, const int32* vdims)
  95.                                 :dimn(from_sds->dimn) {
  96.                                 std::copy_n(vdims, from_sds->dimn, dims);
  97.                                 size_t tot = 1;
  98.                                 for (int i = 0; i < dimn; i++)
  99.                                         tot *= dims[i];
  100.                                 data = new Tp[tot];
  101.                         }
  102.                         ~Data_array() { delete[] data; }
  103.                 };
  104.                 int32 sdsid;
  105.                 char name[256];
  106.                 int32 dimn;
  107.                 int32 dims[MAX_VAR_DIMS];
  108.                 int32 dattype;
  109.                 int32 nattr;
  110.                 template<class Tp>
  111.                 Data_array<Tp> get() {
  112.                         Data_array<Tp> res(this, dims);
  113.                         SDreaddata(sdsid, All_begin, nullptr, dims, res.data);
  114.                         return res;
  115.                 }
  116.                 template<class Tp>
  117.                 Data_array<Tp> get(const std::vector<int32>& start, const std::vector<int32>& cntrd) {
  118.                         auto mvas = start, mvac = cntrd;
  119.                         Data_array<Tp> res(this, cntrd.data());
  120.                         SDreaddata(sdsid, mvas.data(), nullptr, mvac.data(), res.data);
  121.                         return res;
  122.                 }
  123.                 template<class Tp>
  124.                 Attribute<Tp> attribute(int32 attr_index) {
  125.                         return Attribute<Tp>(sdsid, attr_index);
  126.                 }
  127.                 template<class Tp>
  128.                 Attribute<Tp> attribute(std::string_view attrname) {
  129.                         return Attribute<Tp>(sdsid, SDfindattr(sdsid, attrname.data()));
  130.                 }
  131.                 SDS(int sds_id)
  132.                         :sdsid(sds_id) {
  133.                         SDgetinfo(sds_id, name, &dimn, dims, &dattype, &nattr);
  134.                 }
  135.                 ~SDS() { SDendaccess(sdsid); }
  136.         };
  137.         SDS select(int32 index) {
  138.                 return SDS(SDselect(sdid, index));
  139.         }
  140.         SDS select(std::string_view sdsname) {
  141.                 return SDS(SDselect(sdid, SDnametoindex(sdid, sdsname.data())));
  142.         }
  143.         template<class Tp>
  144.                 Attribute<Tp> attribute(int32 attr_index) {
  145.                 return Attribute<Tp>(sdid, attr_index);
  146.         }
  147.         template<class Tp>
  148.         Attribute<Tp> attribute(std::string_view attrname) {
  149.                 return Attribute<Tp>(sdid, SDfindattr(sdid, attrname.data()));
  150.         }
  151.         SDfile(std::string_view filename)
  152.                 :sdid(SDstart(filename.data(), DFACC_READ)) {
  153.                 SDfileinfo(sdid, &ndataset, &nattr);
  154.         }
  155.         ~SDfile() { SDend(sdid); }
  156. };

  157. std::map<std::string, double> Center_Wl_in_um{
  158.         {"1", (0.62 + 0.67) / 2},
  159.         {"2", (0.841 + 0.876) / 2},
  160.         {"3", (0.459 + 0.479) / 2},
  161.         {"4", (0.545 + 0.565) / 2},
  162.         {"5", (1.23 + 1.25) / 2},
  163.         {"6", (1.628 + 1.652) / 2},
  164.         {"7", (2.105 + 2.155) / 2},
  165.         {"8", (0.405 + 0.42) / 2},
  166.         {"9", (0.438 + 0.448) / 2},
  167.         {"10", (0.483 + 0.493) / 2},
  168.         {"11", (0.526 + 0.536) / 2},
  169.         {"12", (0.546 + 0.556) / 2},
  170.         {"13hi", (0.662 + 0.672) / 2},
  171.         {"13lo", (0.662 + 0.672) / 2},
  172.         {"14hi", (0.673 + 0.683) / 2},
  173.         {"14lo", (0.673 + 0.683) / 2},
  174.         {"15", (0.743 + 0.753) / 2},
  175.         {"16", (0.862 + 0.877) / 2},
  176.         {"17", (0.89 + 0.92) / 2},
  177.         {"18", (0.931 + 0.941) / 2},
  178.         {"19", (0.915 + 0.965) / 2},
  179.         {"20", (3.66 + 3.84) / 2},
  180.         {"21", (3.929 + 3.989) / 2},
  181.         {"22", (3.929 + 3.989) / 2},
  182.         {"23", (4.02 + 4.08) / 2},
  183.         {"24", (4.433 + 4.498) / 2},
  184.         {"25", (4.482 + 4.549) / 2},
  185.         {"26", (1.36 + 1.39) / 2},
  186.         {"27", (6.535 + 6.895) / 2},
  187.         {"28", (7.175 + 7.475) / 2},
  188.         {"29", (8.4 + 8.7) / 2},
  189.         {"30", (9.58 + 9.88) / 2},
  190.         {"31", (10.78 + 11.28) / 2},
  191.         {"32", (11.77 + 12.27) / 2},
  192.         {"33", (13.185 + 13.485) / 2},
  193.         {"34", (13.485 + 13.785) / 2},
  194.         {"35", (13.785 + 14.085) / 2},
  195.         {"36", (14.085 + 14.385) / 2}
  196. };

  197. template<class Tp>
  198. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw);

  199. int main(int argc, char** argv) {
  200.         using namespace std;
  201.         if (argc < 2)
  202.                 throw invalid_argument("必须在 argv[1] 提供文件名");
  203.         auto lasttime = chrono::high_resolution_clock::now();
  204.         SDfile file(argv[1]);
  205.         /*
  206.          Latitude,Longitude,EV_1KM_RefSB,EV_1KM_RefSB_Uncert_Indexes,EV_1KM_Emissive,
  207.          EV_1KM_Emissive_Uncert_Indexes,EV_250_Aggr1km_RefSB,EV_250_Aggr1km_RefSB_Uncert_Indexes,
  208.          EV_250_Aggr1km_RefSB_Samples_Used,EV_500_Aggr1km_RefSB,EV_500_Aggr1km_RefSB_Uncert_Indexes,
  209.          EV_500_Aggr1km_RefSB_Samples_Used,Height,SensorZenith,SensorAzimuth,
  210.          Range,SolarZenith,SolarAzimuth,gflags,EV_Band26,EV_Band26_Uncert_Indexes,Band_250M,
  211.          Band_500M,Band_1KM_RefSB,Band_1KM_Emissive,Noise in Thermal Detectors,
  212.          Change in relative responses of thermal detectors,DC Restore Change for Thermal Bands,
  213.          DC Restore Change for Reflective 250m Bands,DC Restore Change for Reflective 500m Bands,
  214.          DC Restore Change for Reflective 1km Bands
  215.         */
  216.         string main_sdsname = "EV_1KM_Emissive";
  217.         auto sds = file.select(main_sdsname);
  218.         auto fulldat = sds.get<uint16>();
  219.         auto getbandname = [&] (int bdid) {
  220.                 string bandname;
  221.                 auto bds = sds.attribute<char>("band_names");
  222.                 int cnt = 0;
  223.                 for (auto ch : bds.data)
  224.                         if (ch == ',')
  225.                         {
  226.                                 if (cnt == bdid)
  227.                                         break;
  228.                                 bandname.clear();
  229.                                 ++cnt;
  230.                         }
  231.                         else
  232.                                 bandname.push_back(ch);
  233.                 return bandname;
  234.         };
  235.         auto readband = [&] (int bdid) {
  236.                 auto emmmat = new float[sds.dims[1] * sds.dims[2]];
  237.                 string bandname = getbandname(bdid);
  238.                 float ro = sds.attribute<float>("radiance_offsets").data[bdid],
  239.                 rs = sds.attribute<float>("radiance_scales").data[bdid];
  240.                 for (int i = 0; i < sds.dims[1]; i++)
  241.                         for (int j = 0; j < sds.dims[2]; j++)
  242.                                 emmmat[i * sds.dims[2] + j] = (fulldat[{bdid, i, j}] - ro) * rs;
  243.                 // for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  244.                 //         emmmat[i] = brtemp(emmmat[i], Center_Wl_in_um.at(bandname));
  245.                 return emmmat;
  246.         };
  247.         int bdid = 0;
  248.         string lbinfo = main_sdsname + " Band\\d" + getbandname(bdid) + "\\u";
  249.         lbinfo += " Anomaly";
  250.         //lbinfo += " " + to_string(Center_Wl_in_um.at(getbandname(bdid))) + "um";
  251.         auto emmmat = readband(bdid);
  252.         string outname = string("'") + argv[1] + "-";
  253.         for (auto ch : lbinfo)
  254.                 if (ch == ' ')
  255.                         outname.push_back('-');
  256.                 else if (ch != '\\')
  257.                         outname.push_back(ch);
  258.         outname += ".png'";
  259.         auto solarzsds = file.select("SolarZenith");
  260.         auto solarzl0 = solarzsds.get<int16>();
  261.         SDfile::SDS::Data_array<float> solarzl1(&solarzsds, solarzsds.dims);
  262.         for (int i = 0; i < solarzl0.dims[0] * solarzl0.dims[1]; i++)
  263.                 solarzl1.data[i] = solarzl0.data[i] / 1e2;
  264.         auto solarzl2 = interp<float>(solarzl1, sds.dims[1], sds.dims[2]);
  265.         auto latsds = file.select("Latitude");
  266.         auto latl1 = latsds.get<float>();
  267.         auto latl2 = interp<float>(latl1, sds.dims[1], sds.dims[2]);
  268.         auto lonsds = file.select("Longitude");
  269.         auto lonl1 = lonsds.get<float>();
  270.         for (int i = 0; i < lonl1.dims[0] * lonl1.dims[1]; i++)
  271.                 if (lonl1.data[i] < 0)
  272.                         lonl1.data[i] += 360;
  273.         auto lonl2 = interp<float>(lonl1, sds.dims[1], sds.dims[2]);
  274.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  275.                 emmmat[i] = brtemp(emmmat[i] / cos(Deg2rad * solarzl2[i]),
  276.                         Center_Wl_in_um.at(getbandname(bdid)));
  277.         float avg = 0;
  278.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  279.                 avg += emmmat[i] / sds.dims[1];
  280.         avg /= sds.dims[2];
  281.         auto tmp = file.attribute<char>("CoreMetadata.0").data;
  282.         string coremeta(tmp.begin(), tmp.end());
  283.         auto getcmt = [&] (string obj) {
  284.                 auto posm = coremeta.find("OBJECT                 = " + obj);
  285.                 auto pos = coremeta.find("VALUE                = ", posm);
  286.                 int offset = 23, backoff = 0;
  287.                 if (coremeta[pos + offset] == '"')
  288.                 {
  289.                         ++offset;
  290.                         ++backoff;
  291.                 }
  292.                 auto end = coremeta.find('\n', pos + offset);
  293.                 return coremeta.substr(pos + offset, end - pos - offset - backoff);
  294.         };
  295.         string device = getcmt("ASSOCIATEDSENSORSHORTNAME") + "/" +
  296.                 getcmt("ASSOCIATEDPLATFORMSHORTNAME");
  297.         string endtime = getcmt("RANGEENDINGDATE") + " " +
  298.                 getcmt("RANGEENDINGTIME");
  299.         while (endtime.back() == '0')
  300.                 endtime.pop_back();
  301.         endtime.pop_back();
  302.         endtime += "\\uUTC\\d";
  303.         cout << "读取数据用时: " <<
  304.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  305.                         - lasttime).count() / 1e6 << " s\n";
  306.         lasttime = chrono::high_resolution_clock::now();
  307. #ifdef PNG_OUTPUT
  308.         if (cpgopen("tmp.ps/VCPS") < 0)
  309. #else
  310.         if (cpgopen("/XWINDOW") < 0)
  311. #endif
  312.                 throw runtime_error("打开PGPLOT设备错误");
  313.         cpgbbuf();
  314.         auto latmmx =
  315.                 minmax_element(latl1.data, latl1.data + latl1.dims[0] * latl1.dims[1]),
  316.         lonmmx =
  317.                 minmax_element(lonl1.data, lonl1.data + lonl1.dims[0] * lonl1.dims[1]);
  318.         cpgenv(*lonmmx.first, *lonmmx.second, *latmmx.first, *latmmx.second
  319.                 , 1, 1);
  320.         //cpgenv(117, 135, 10, 25, 1, 1);
  321.         cpglab("Lon", "Lat", argv[1]);
  322.         cpgmtxt("R", 1, 0, 0, lbinfo.c_str());
  323.         cpgmtxt("B", 2.5, 0.15, 0, device.c_str());
  324.         cpgmtxt("B", 2.5, 0.6, 0, endtime.c_str());
  325.         set_color();
  326.         cpgscir(lowcol, hicol);
  327.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  328.                 {
  329.                         if (isnan(emmmat[i]))
  330.                                 continue;
  331.                         int col = color_brtemp(emmmat[i] - avg);
  332.                         int rind = i / sds.dims[2], cind = i % sds.dims[2];
  333.                         double colrng = (float)abs(cind - sds.dims[2] / 2) / sds.dims[2];
  334.                         double siz = 8e-3 * exp(3.5 * colrng + 0.8 * sqrt(abs(latl2[i]) * 1.3e-4)) +
  335.                                 4e-4 * exp(4 * pow(colrng, 2));
  336.                         cpgpixl(&col, 1, 1, 1, 1, 1, 1, lonl2[i],
  337.                                 lonl2[i] + siz, latl2[i], latl2[i] + siz);
  338.                 }
  339.         cpgwedg("RI", 2, 3, low, high, "^C");
  340.         cpgebuf();
  341.         cpgend();
  342.         cout << "PGPLOT输出用时: " <<
  343.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  344.                         - lasttime).count() / 1e6 << " s\n";
  345.         lasttime = chrono::high_resolution_clock::now();
  346. #ifdef PNG_OUTPUT
  347.         system(("magick -density 240 tmp.ps " + outname).c_str());
  348.         cout << "PNG转换用时: " <<
  349.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  350.                         - lasttime).count() / 1e6 << " s\n";
  351.         cout << "输出到PNG文件: " << outname << endl;
  352.         system("rm tmp.ps");
  353. #endif
  354.         delete[] solarzl2;
  355.         delete[] latl2;
  356.         delete[] lonl2;
  357.         delete[] emmmat;
  358.         return 0;
  359. }

  360. template<class Tp>
  361. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw) {
  362.         auto res = new Tp[dsth * dstw];
  363.         res[0] = init[{0, 0}];
  364.         res[dsth * dstw - 1] = init[{init.dims[0] - 1, init.dims[1] - 1}];
  365.         double deltaX = double(init.dims[0] - 1) / (dsth - 1), deltaY = double(init.dims[1] - 1) / (dstw - 1);
  366.         for (int i = 0; i < dsth; i++)
  367.                 for (int j = 0; j < dstw; j++)
  368.                         if ((i || j) && (i != dsth - 1 || j != dstw - 1))
  369.                         {
  370.                                 double mappedX = deltaX * i, mappedY = deltaY * j;
  371.                                 double cX = mappedX - floor(mappedX), cY = mappedY - floor(mappedY);
  372.                                 int x0 = mappedX, x1 = std::min<int>(ceil(mappedX), init.dims[0] - 1);
  373.                                 int y0 = mappedY, y1 = std::min<int>(ceil(mappedY), init.dims[1] - 1);
  374.                                 res[i * dstw + j] = (1 - cX) * (1 - cY) * init[{x0, y0}] +
  375.                                         (1 - cX) * cY * init[{x0, y1}] +
  376.                                                 cX * (1 - cY) * init[{x1, y0}] +
  377.                                                         cX * cY * init[{x1, y1}];
  378.                         }
  379.         return res;
  380. }
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-22 21:27 | 显示全部楼层
本帖最后由 wfIRstzhang 于 2026-2-22 21:38 编辑

这几张图观感不好,不过主要是看看不同波段对低云的体现







  1. #include <algorithm>
  2. #include <chrono>
  3. #include <cmath>
  4. #include <complex>
  5. #include <cpgplot.h>
  6. #include <iostream>
  7. #include <limits>
  8. #include <map>
  9. #include <mfhdf.h>
  10. #include <numbers>
  11. #include <stdexcept>
  12. #include <type_traits>
  13. #include <vector>

  14. #define PNG_OUTPUT

  15. constexpr double Hc_k = 1.4387768775039337e4;
  16. constexpr double H2c_2 = 1.1910429723971884140794892e8;
  17. constexpr double Deg2rad = std::numbers::pi / 180;
  18. constexpr double K2c = -273.15;
  19. static float low = -60, high = 40;
  20. static int lowcol = 16, hicol = 100;

  21. constexpr double brtemp(double bt, double lam_um) {
  22.         return Hc_k / lam_um / std::log(H2c_2 / pow(lam_um, 5) / bt + 1);
  23. }

  24. int color_brtemp(double brtempC) {
  25.         double zonnap = std::clamp((brtempC - low) / (high - low), 0., 1.);
  26.         int mincol, maxcol;
  27.         cpgqcir(&mincol, &maxcol);
  28.         return mincol + (maxcol - mincol) * zonnap;
  29. }

  30. void set_color() {
  31.         // cpgscr(16, 0.5, 0.5, 0.75);
  32.         // cpgscr(15, 0.4, 0.4, 0.6);
  33.         // cpgscr(14, 0.3, 0.3, 0.45);
  34.         // cpgscr(13, 0.2, 0.2, 0.3);
  35.         // cpgscr(12, 0.1, 0.1, 0.15);
  36.         int midlen = (hicol - lowcol) / 2;
  37.         for (int i = lowcol; i <= lowcol + midlen; i++)
  38.         {
  39.                 float base = float(i - lowcol) / midlen;
  40.                 cpgscr(i, base, base, base);
  41.         }
  42.         for (int i = lowcol + midlen + 1; i <= lowcol + midlen * 2; i++)
  43.         {
  44.                 float base = float(lowcol + midlen * 2 - i) / midlen;
  45.                 cpgscr(i, base * 0.6, base * 0.6, base);
  46.         }
  47. }

  48. template<int32 Nt>
  49. using SDtype =
  50.         std::conditional_t<Nt == 3, int8,
  51.         std::conditional_t<Nt == 4, char8,
  52.         std::conditional_t<Nt == 5, float32,
  53.         std::conditional_t<Nt == 6, float64,
  54.         std::conditional_t<Nt == 20, int8,
  55.         std::conditional_t<Nt == 21, uint8,
  56.         std::conditional_t<Nt == 22, int16,
  57.         std::conditional_t<Nt == 23, uint16,
  58.         std::conditional_t<Nt == 24, int32,
  59.         std::conditional_t<Nt == 25, uint32, void>>>>>>>>>>;

  60. struct SDfile {
  61.         int32 sdid;
  62.         int32 ndataset, nattr;
  63.         template<class Tp>
  64.         struct Attribute {
  65.                 int32 obj_id, index;
  66.                 int32 type, count;
  67.                 char name[256];
  68.                 std::vector<Tp> data;
  69.                 Attribute(int32 pobj_id, int32 pindex)
  70.                         :obj_id(pobj_id), index(pindex) {
  71.                         SDattrinfo(pobj_id, pindex, name, &type, &count);
  72.                         data.assign(count, Tp());
  73.                         SDreadattr(obj_id, index, data.data());
  74.                 }
  75.         };
  76.         struct SDS {
  77.                 int32 All_begin[MAX_VAR_DIMS]{};
  78.                 template<class Tp>
  79.                 struct Data_array {
  80.                         int32 dimn;
  81.                         int32 dims[MAX_VAR_DIMS];
  82.                         Tp* data;
  83.                         Tp operator[] (std::initializer_list<int32> dimensions) const {
  84.                                 auto it = dimensions.end();
  85.                                 size_t dimit = dimn - 1, pnow = 1, datanow = 0;
  86.                                 do
  87.                                 {
  88.                                         --it;
  89.                                         datanow += *it * pnow;
  90.                                         pnow *= dims[dimit--];
  91.                                 } while (it != dimensions.begin());
  92.                                 return data[datanow];
  93.                         }
  94.                         Data_array(const SDS* from_sds, const int32* vdims)
  95.                                 :dimn(from_sds->dimn) {
  96.                                 std::copy_n(vdims, from_sds->dimn, dims);
  97.                                 size_t tot = 1;
  98.                                 for (int i = 0; i < dimn; i++)
  99.                                         tot *= dims[i];
  100.                                 data = new Tp[tot];
  101.                         }
  102.                         ~Data_array() { delete[] data; }
  103.                 };
  104.                 int32 sdsid;
  105.                 char name[256];
  106.                 int32 dimn;
  107.                 int32 dims[MAX_VAR_DIMS];
  108.                 int32 dattype;
  109.                 int32 nattr;
  110.                 template<class Tp>
  111.                 Data_array<Tp> get() {
  112.                         Data_array<Tp> res(this, dims);
  113.                         SDreaddata(sdsid, All_begin, nullptr, dims, res.data);
  114.                         return res;
  115.                 }
  116.                 template<class Tp>
  117.                 Data_array<Tp> get(const std::vector<int32>& start, const std::vector<int32>& cntrd) {
  118.                         auto mvas = start, mvac = cntrd;
  119.                         Data_array<Tp> res(this, cntrd.data());
  120.                         SDreaddata(sdsid, mvas.data(), nullptr, mvac.data(), res.data);
  121.                         return res;
  122.                 }
  123.                 template<class Tp>
  124.                 Attribute<Tp> attribute(int32 attr_index) {
  125.                         return Attribute<Tp>(sdsid, attr_index);
  126.                 }
  127.                 template<class Tp>
  128.                 Attribute<Tp> attribute(std::string_view attrname) {
  129.                         return Attribute<Tp>(sdsid, SDfindattr(sdsid, attrname.data()));
  130.                 }
  131.                 SDS(int sds_id)
  132.                         :sdsid(sds_id) {
  133.                         SDgetinfo(sds_id, name, &dimn, dims, &dattype, &nattr);
  134.                 }
  135.                 ~SDS() { SDendaccess(sdsid); }
  136.         };
  137.         SDS select(int32 index) {
  138.                 return SDS(SDselect(sdid, index));
  139.         }
  140.         SDS select(std::string_view sdsname) {
  141.                 return SDS(SDselect(sdid, SDnametoindex(sdid, sdsname.data())));
  142.         }
  143.         template<class Tp>
  144.                 Attribute<Tp> attribute(int32 attr_index) {
  145.                 return Attribute<Tp>(sdid, attr_index);
  146.         }
  147.         template<class Tp>
  148.         Attribute<Tp> attribute(std::string_view attrname) {
  149.                 return Attribute<Tp>(sdid, SDfindattr(sdid, attrname.data()));
  150.         }
  151.         SDfile(std::string_view filename)
  152.                 :sdid(SDstart(filename.data(), DFACC_READ)) {
  153.                 SDfileinfo(sdid, &ndataset, &nattr);
  154.         }
  155.         ~SDfile() { SDend(sdid); }
  156. };

  157. std::map<std::string, double> Center_Wl_in_um{
  158.         {"1", (0.62 + 0.67) / 2},
  159.         {"2", (0.841 + 0.876) / 2},
  160.         {"3", (0.459 + 0.479) / 2},
  161.         {"4", (0.545 + 0.565) / 2},
  162.         {"5", (1.23 + 1.25) / 2},
  163.         {"6", (1.628 + 1.652) / 2},
  164.         {"7", (2.105 + 2.155) / 2},
  165.         {"8", (0.405 + 0.42) / 2},
  166.         {"9", (0.438 + 0.448) / 2},
  167.         {"10", (0.483 + 0.493) / 2},
  168.         {"11", (0.526 + 0.536) / 2},
  169.         {"12", (0.546 + 0.556) / 2},
  170.         {"13hi", (0.662 + 0.672) / 2},
  171.         {"13lo", (0.662 + 0.672) / 2},
  172.         {"14hi", (0.673 + 0.683) / 2},
  173.         {"14lo", (0.673 + 0.683) / 2},
  174.         {"15", (0.743 + 0.753) / 2},
  175.         {"16", (0.862 + 0.877) / 2},
  176.         {"17", (0.89 + 0.92) / 2},
  177.         {"18", (0.931 + 0.941) / 2},
  178.         {"19", (0.915 + 0.965) / 2},
  179.         {"20", (3.66 + 3.84) / 2},
  180.         {"21", (3.929 + 3.989) / 2},
  181.         {"22", (3.929 + 3.989) / 2},
  182.         {"23", (4.02 + 4.08) / 2},
  183.         {"24", (4.433 + 4.498) / 2},
  184.         {"25", (4.482 + 4.549) / 2},
  185.         {"26", (1.36 + 1.39) / 2},
  186.         {"27", (6.535 + 6.895) / 2},
  187.         {"28", (7.175 + 7.475) / 2},
  188.         {"29", (8.4 + 8.7) / 2},
  189.         {"30", (9.58 + 9.88) / 2},
  190.         {"31", (10.78 + 11.28) / 2},
  191.         {"32", (11.77 + 12.27) / 2},
  192.         {"33", (13.185 + 13.485) / 2},
  193.         {"34", (13.485 + 13.785) / 2},
  194.         {"35", (13.785 + 14.085) / 2},
  195.         {"36", (14.085 + 14.385) / 2}
  196. };

  197. template<class Tp>
  198. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw);

  199. int main(int argc, char** argv) {
  200.         using namespace std;
  201.         if (argc < 2)
  202.                 throw invalid_argument("必须在 argv[1] 提供文件名");
  203.         auto lasttime = chrono::high_resolution_clock::now();
  204.         SDfile file(argv[1]);
  205.         /*
  206.          Latitude,Longitude,EV_1KM_RefSB,EV_1KM_RefSB_Uncert_Indexes,EV_1KM_Emissive,
  207.          EV_1KM_Emissive_Uncert_Indexes,EV_250_Aggr1km_RefSB,EV_250_Aggr1km_RefSB_Uncert_Indexes,
  208.          EV_250_Aggr1km_RefSB_Samples_Used,EV_500_Aggr1km_RefSB,EV_500_Aggr1km_RefSB_Uncert_Indexes,
  209.          EV_500_Aggr1km_RefSB_Samples_Used,Height,SensorZenith,SensorAzimuth,
  210.          Range,SolarZenith,SolarAzimuth,gflags,EV_Band26,EV_Band26_Uncert_Indexes,Band_250M,
  211.          Band_500M,Band_1KM_RefSB,Band_1KM_Emissive,Noise in Thermal Detectors,
  212.          Change in relative responses of thermal detectors,DC Restore Change for Thermal Bands,
  213.          DC Restore Change for Reflective 250m Bands,DC Restore Change for Reflective 500m Bands,
  214.          DC Restore Change for Reflective 1km Bands
  215.         */
  216.         string main_sdsname = "EV_1KM_Emissive";
  217.         auto sds = file.select(main_sdsname);
  218.         auto fulldat = sds.get<uint16>();
  219.         auto getbandname = [&] (int bdid) {
  220.                 string bandname;
  221.                 auto bds = sds.attribute<char>("band_names");
  222.                 int cnt = 0;
  223.                 for (auto ch : bds.data)
  224.                         if (ch == ',')
  225.                         {
  226.                                 if (cnt == bdid)
  227.                                         break;
  228.                                 bandname.clear();
  229.                                 ++cnt;
  230.                         }
  231.                         else
  232.                                 bandname.push_back(ch);
  233.                 return bandname;
  234.         };
  235.         auto readband = [&] (int bdid) {
  236.                 auto emmmat = new float[sds.dims[1] * sds.dims[2]];
  237.                 string bandname = getbandname(bdid);
  238.                 float ro = sds.attribute<float>("radiance_offsets").data[bdid],
  239.                 rs = sds.attribute<float>("radiance_scales").data[bdid];
  240.                 for (int i = 0; i < sds.dims[1]; i++)
  241.                         for (int j = 0; j < sds.dims[2]; j++)
  242.                                 emmmat[i * sds.dims[2] + j] = (fulldat[{bdid, i, j}] - ro) * rs;
  243.                 for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  244.                         emmmat[i] = brtemp(emmmat[i], Center_Wl_in_um.at(bandname));
  245.                 return emmmat;
  246.         };
  247.         int bdid = 14;
  248.         string lbinfo = main_sdsname + " Band\\d" + getbandname(bdid) + "\\u";
  249.         lbinfo += " Anomaly";
  250.         //lbinfo += " " + to_string(Center_Wl_in_um.at(getbandname(bdid))) + "um";
  251.         auto emmmat = readband(bdid);
  252.         string outname = string("'") + argv[1] + "-";
  253.         for (auto ch : lbinfo)
  254.                 if (ch == ' ')
  255.                         outname.push_back('-');
  256.                 else if (ch != '\\')
  257.                         outname.push_back(ch);
  258.         outname += ".png'";
  259.         auto solarzsds = file.select("SolarZenith");
  260.         auto solarzl0 = solarzsds.get<int16>();
  261.         SDfile::SDS::Data_array<float> solarzl1(&solarzsds, solarzsds.dims);
  262.         for (int i = 0; i < solarzl0.dims[0] * solarzl0.dims[1]; i++)
  263.                 solarzl1.data[i] = solarzl0.data[i] / 1e2;
  264.         auto solarzl2 = interp<float>(solarzl1, sds.dims[1], sds.dims[2]);
  265.         auto latsds = file.select("Latitude");
  266.         auto latl1 = latsds.get<float>();
  267.         auto latl2 = interp<float>(latl1, sds.dims[1], sds.dims[2]);
  268.         auto lonsds = file.select("Longitude");
  269.         auto lonl1 = lonsds.get<float>();
  270.         for (int i = 0; i < lonl1.dims[0] * lonl1.dims[1]; i++)
  271.                 if (lonl1.data[i] < 0)
  272.                         lonl1.data[i] += 360;
  273.         auto lonl2 = interp<float>(lonl1, sds.dims[1], sds.dims[2]);
  274.         // for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  275.         //         emmmat[i] = brtemp(emmmat[i] / cos(Deg2rad * solarzl2[i]),
  276.         //                 Center_Wl_in_um.at(getbandname(bdid)));
  277.         float avg = 0;
  278.         int nnancnt = 0;
  279.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  280.                 if (!isnan(emmmat[i]))
  281.                 {
  282.                         avg += emmmat[i];
  283.                         ++nnancnt;
  284.                 }
  285.         avg /= nnancnt;
  286.         auto tmp = file.attribute<char>("CoreMetadata.0").data;
  287.         string coremeta(tmp.begin(), tmp.end());
  288.         auto getcmt = [&] (string obj) {
  289.                 auto posm = coremeta.find("OBJECT                 = " + obj);
  290.                 auto pos = coremeta.find("VALUE                = ", posm);
  291.                 int offset = 23, backoff = 0;
  292.                 if (coremeta[pos + offset] == '"')
  293.                 {
  294.                         ++offset;
  295.                         ++backoff;
  296.                 }
  297.                 auto end = coremeta.find('\n', pos + offset);
  298.                 return coremeta.substr(pos + offset, end - pos - offset - backoff);
  299.         };
  300.         string device = getcmt("ASSOCIATEDSENSORSHORTNAME") + "/" +
  301.                 getcmt("ASSOCIATEDPLATFORMSHORTNAME");
  302.         string endtime = getcmt("RANGEENDINGDATE") + " " +
  303.                 getcmt("RANGEENDINGTIME");
  304.         while (endtime.back() == '0')
  305.                 endtime.pop_back();
  306.         endtime.pop_back();
  307.         endtime += "\\uUTC\\d";
  308.         cout << "读取数据用时: " <<
  309.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  310.                         - lasttime).count() / 1e6 << " s\n";
  311.         lasttime = chrono::high_resolution_clock::now();
  312. #ifdef PNG_OUTPUT
  313.         if (cpgopen("tmp.ps/VCPS") < 0)
  314. #else
  315.         if (cpgopen("/XWINDOW") < 0)
  316. #endif
  317.                 throw runtime_error("打开PGPLOT设备错误");
  318.         cpgbbuf();
  319.         auto latmmx =
  320.                 minmax_element(latl1.data, latl1.data + latl1.dims[0] * latl1.dims[1]),
  321.         lonmmx =
  322.                 minmax_element(lonl1.data, lonl1.data + lonl1.dims[0] * lonl1.dims[1]);
  323.         cpgenv(*lonmmx.first, *lonmmx.second, *latmmx.first, *latmmx.second
  324.                 , 1, 1);
  325.         //cpgenv(117, 135, 10, 25, 1, 1);
  326.         cpglab("Lon", "Lat", argv[1]);
  327.         cpgmtxt("R", 1, 0, 0, lbinfo.c_str());
  328.         cpgmtxt("B", 2.5, 0.15, 0, device.c_str());
  329.         cpgmtxt("B", 2.5, 0.6, 0, endtime.c_str());
  330.         set_color();
  331.         cpgscir(lowcol, hicol);
  332.         for (int i = 0; i < sds.dims[1] * sds.dims[2]; i++)
  333.                 {
  334.                         if (isnan(emmmat[i]))
  335.                                 continue;
  336.                         int col = color_brtemp(emmmat[i] - avg);
  337.                         int rind = i / sds.dims[2], cind = i % sds.dims[2];
  338.                         double colrng = (float)abs(cind - sds.dims[2] / 2) / sds.dims[2];
  339.                         double siz = 8e-3 * exp(3.5 * colrng + 0.8 * sqrt(abs(latl2[i]) * 1.3e-4)) +
  340.                                 4e-4 * exp(4 * pow(colrng, 2));
  341.                         cpgpixl(&col, 1, 1, 1, 1, 1, 1, lonl2[i],
  342.                                 lonl2[i] + siz, latl2[i], latl2[i] + siz);
  343.                 }
  344.         cpgwedg("RI", 2, 3, low, high, "^C");
  345.         cpgebuf();
  346.         cpgend();
  347.         cout << "PGPLOT输出用时: " <<
  348.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  349.                         - lasttime).count() / 1e6 << " s\n";
  350.         lasttime = chrono::high_resolution_clock::now();
  351. #ifdef PNG_OUTPUT
  352.         system(("magick -density 240 tmp.ps " + outname).c_str());
  353.         cout << "PNG转换用时: " <<
  354.                 chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now()
  355.                         - lasttime).count() / 1e6 << " s\n";
  356.         cout << "输出到PNG文件: " << outname << endl;
  357.         system("rm tmp.ps");
  358. #endif
  359.         delete[] solarzl2;
  360.         delete[] latl2;
  361.         delete[] lonl2;
  362.         delete[] emmmat;
  363.         return 0;
  364. }

  365. template<class Tp>
  366. Tp* interp(const SDfile::SDS::Data_array<Tp>& init, int dsth, int dstw) {
  367.         auto res = new Tp[dsth * dstw];
  368.         res[0] = init[{0, 0}];
  369.         res[dsth * dstw - 1] = init[{init.dims[0] - 1, init.dims[1] - 1}];
  370.         double deltaX = double(init.dims[0] - 1) / (dsth - 1), deltaY = double(init.dims[1] - 1) / (dstw - 1);
  371.         for (int i = 0; i < dsth; i++)
  372.                 for (int j = 0; j < dstw; j++)
  373.                         if ((i || j) && (i != dsth - 1 || j != dstw - 1))
  374.                         {
  375.                                 double mappedX = deltaX * i, mappedY = deltaY * j;
  376.                                 double cX = mappedX - floor(mappedX), cY = mappedY - floor(mappedY);
  377.                                 int x0 = mappedX, x1 = std::min<int>(ceil(mappedX), init.dims[0] - 1);
  378.                                 int y0 = mappedY, y1 = std::min<int>(ceil(mappedY), init.dims[1] - 1);
  379.                                 res[i * dstw + j] = (1 - cX) * (1 - cY) * init[{x0, y0}] +
  380.                                         (1 - cX) * cY * init[{x0, y1}] +
  381.                                                 cX * (1 - cY) * init[{x1, y0}] +
  382.                                                         cX * cY * init[{x1, y1}];
  383.                         }
  384.         return res;
  385. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-22 21:39 | 显示全部楼层
wfIRstzhang 发表于 2026-2-22 21:27
这几张图观感不好,不过主要是看看不同波段对低云的体现

所以伪VIS要用一个中波红外显示低云
SIGNATURE

1

主题

15

回帖

145

积分

热带低压

自定义头衔测试

积分
145
 楼主| 发表于 2026-2-23 16:49 | 显示全部楼层










本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SIGNATURE
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|TY_Board论坛

GMT+8, 2026-3-22 06:54 , Processed in 0.064260 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表