找回密码
 立即注册
搜索
查看: 53|回复: 2

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

[复制链接]

1

主题

3

回帖

95

积分

热带扰动-TCFA

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

本帖子中包含更多资源

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

×
S I G N A T U R E

1

主题

3

回帖

95

积分

热带扰动-TCFA

积分
95
 楼主| 发表于 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
S I G N A T U R E

1

主题

3

回帖

95

积分

热带扰动-TCFA

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

本帖子中包含更多资源

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

×
S I G N A T U R E
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2026-2-21 05:34 , Processed in 0.062929 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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