You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1246 lines
38 KiB
C++

1 month ago
#include "StdAfx.h"
#include "KEDAlgorithm.h"
#include <windows.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
template <typename T>
void qDeleteAll(std::vector<T*>& vec)
{
for (auto* p : vec) {
delete p;
}
vec.clear();
}
// <20><> std::string תΪ std::wstring
static std::wstring utf8_to_wstring(const std::string& s) {
if (s.empty()) return {};
int needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), NULL, 0);
std::wstring out(needed, 0);
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), &out[0], needed);
return out;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD><D8B6>ֽڱ<D6BD><DAB1><EFBFBD> (GBK/ANSI) ת<><D7AA> Unicode
static std::wstring ansi_to_wstring(const std::string& s) {
if (s.empty()) return {};
int needed = MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), NULL, 0);
std::wstring out(needed, 0);
MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), &out[0], needed);
return out;
}
// <20><><EFBFBD><EFBFBD> facies_boundaries.exe
bool RunFaciesBoundaries(
const std::string& exePath,
const std::string& grdPath,
const std::string& dfdPath,
std::string& outStdout,
DWORD& outExitCode,
DWORD timeoutMs,
std::atomic<bool>* cancelFlag = nullptr)
{
outStdout.clear();
outExitCode = (DWORD)-1;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>
std::wstringstream cmd;
cmd << L"\"" << ansi_to_wstring(exePath) << L"\" ";
cmd << L"\"" << ansi_to_wstring(grdPath) << L"\" ";
cmd << L"\"" << ansi_to_wstring(dfdPath) << L"\"";
SECURITY_ATTRIBUTES sa{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
HANDLE hRead = NULL, hWrite = NULL;
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) return false;
SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
si.hStdOutput = hWrite;
si.hStdError = hWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
std::wstring cmdStr = cmd.str();
LPWSTR cmdLine = &cmdStr[0];
BOOL ok = CreateProcessW(
NULL, cmdLine, NULL, NULL, TRUE,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi
);
CloseHandle(hWrite); // <20><><EFBFBD><EFBFBD><EFBFBD>̲<EFBFBD><CCB2><EFBFBD>д
if (!ok) {
CloseHandle(hRead);
return false;
}
//<2F>ؼ<EFBFBD><D8BC><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD><EFBFBD><EFBFBD> cancelFlag
const DWORD pollInterval = 100; // ÿ 100ms <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
DWORD totalWait = 0;
bool wasCancelled = false;
while (true) {
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>
if (cancelFlag && cancelFlag->load()) {
TerminateProcess(pi.hProcess, 1);
wasCancelled = true;
break;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ʱ
if (timeoutMs != INFINITE && totalWait >= timeoutMs) {
TerminateProcess(pi.hProcess, 1);
wasCancelled = true;
break;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>˳<EFBFBD>
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
outExitCode = exitCode;
break;
}
// <20>ȴ<EFBFBD>һС<D2BB><D0A1>ʱ<EFBFBD><CAB1>
Sleep(pollInterval);
totalWait += pollInterval;
}
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EABBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
const DWORD bufSize = 4096;
char buffer[bufSize];
DWORD bytesRead = 0;
std::string output;
while (ReadFile(hRead, buffer, bufSize, &bytesRead, NULL) && bytesRead > 0) {
output.append(buffer, bytesRead);
}
outStdout = output;
// <20><><EFBFBD><EFBFBD><EFBFBD>DZ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD> false
bool success = !wasCancelled && (outExitCode == 0);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hRead);
return success;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΰ<EFBFBD>Χ<EFBFBD><CEA7>
static inline void ComputePolygonBBox(const CCurveEx* poly, double& xmin, double& xmax, double& ymin, double& ymax)
{
xmin = 1e20; xmax = -1e20;
ymin = 1e20; ymax = -1e20;
for (int i = 0; i < poly->num; ++i) {
xmin = std::min(xmin, (double)poly->x[i]);
xmax = std::max(xmax, (double)poly->x[i]);
ymin = std::min(ymin, (double)poly->y[i]);
ymax = std::max(ymax, (double)poly->y[i]);
}
}
KEDAlgorithm::KEDAlgorithm()
{
m_DepositionalMap.clear();
}
KEDAlgorithm::~KEDAlgorithm()
{
}
bool KEDAlgorithm::ProcessExistingGrd(
const CString& grdFile, // <20>Ѵ<EFBFBD><D1B4>ڵ<EFBFBD> GRD <20>ļ<EFBFBD>
const CString& kevFile, // <20><><EFBFBD><EFBFBD> KEV <20>ļ<EFBFBD>
CColorBase base,
bool isFaciesBorder,
std::function<void(int completed, int total)> progressCallback)
{
const int TOTAL_STEPS = 4;
auto reportProgress = [&](int step, bool failed = false) {
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
};
m_cancelRequested.store(false);
// <20><><EFBFBD><EFBFBD> GRD <20>ļ<EFBFBD>
std::ifstream fchk(grdFile);
if (!fchk.is_open()) {
reportProgress(0, true);
return false;
}
fchk.close();
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(1);
std::shared_ptr<CXy> pXy = nullptr;
std::vector<CCurve*> pCurves;
if (isFaciesBorder)
{
// --- ׼<><D7BC>·<EFBFBD><C2B7> ---
CSplitPath sp;
sp.SetModuleFileName();
CString xmlPath;
xmlPath.Format("%s%s", sp.GetPath(), "facies");
sp.MakeDirectory(xmlPath);
CString outdfdPath;
outdfdPath.Format("%s%s", xmlPath, "\\facies.dfd");
CString exePath;
exePath.Format("%s%s", sp.GetPath(), "facies_boundaries.exe");
// --- <20><><EFBFBD><EFBFBD> EXE ---
std::string grdPath = grdFile;
std::string dfdPath = std::string(outdfdPath);
std::string procOut;
DWORD exitCode = 0;
bool ran = RunFaciesBoundaries(std::string(exePath), grdPath, dfdPath,
procOut, exitCode, 120000, &m_cancelRequested);
if (!ran || exitCode != 0) {
std::cerr << "<EFBFBD>޷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> facies_boundaries.exe\n";
reportProgress(2, true);
return false;
}
reportProgress(2);
CFile fw;
if (!fw.Open(outdfdPath, CFile::modeRead)) {
reportProgress(2, true);
return false;
}
// <20><>ʼ<EFBFBD><CABC><EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD> pXy
pXy = std::make_shared<CXy>();
pXy->DFD_Read2(fw);
fw.Close();
CPositionList list;
if (pXy->GetElement("Layer:\\Facies", list) > 0)
{
for (POSITION pos = list.GetHeadPosition(); pos != NULL; list.GetNext(pos)) {
COne* pOne = (COne*)(pXy->GetValueList()->GetAt(list.GetAt(pos)));
CCurve* curve = (CCurve*)pOne->GetValue();
pCurves.push_back(curve);
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(3);
}
else
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>߽磬ֱ<E7A3AC><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м䲽<D0BC><EFBFBD><E8A3AC><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
reportProgress(2);
reportProgress(3);
}
// 4. д<><D0B4> KEV <20>ļ<EFBFBD>
if (!GrdToKEVFile(grdFile, kevFile, pCurves, base)) {
reportProgress(3, true);
return false;
}
reportProgress(4);
return true;
}
std::vector<FaciesConfig> KEDAlgorithm::LoadFaciesSettings(const CString& settingsFile,
std::map<std::string, int>& labelMap)
{
std::vector<FaciesConfig> samples;
std::ifstream file((LPCTSTR)settingsFile);
if(!file.is_open()) throw std::runtime_error("<EFBFBD>޷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>: " + settingsFile);
std::string line;
std::getline(file, line); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ
while (std::getline(file, line)) {
if (line.empty()) continue;
std::stringstream ss(line);
std::string name, sCode, sFillCol, sBorderCol, sValue, sX, sY;
// <20>ϸ<EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ͷ˳<CDB7><CBB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>ɫ, <20>߽<EFBFBD>ɫ, <20><>ֵ, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!std::getline(ss, name, ',')) continue;
if (!std::getline(ss, sCode, ',')) continue;
if (!std::getline(ss, sFillCol, ',')) continue;
if (!std::getline(ss, sBorderCol, ',')) continue;
if (!std::getline(ss, sValue, ',')) continue;
if (!std::getline(ss, sX, ',')) continue;
if (!std::getline(ss, sY, ',')) continue;
FaciesConfig config;
config.name = name;
config.code = sCode;
config.fillColor = (COLORREF)std::stoll(sFillCol); // <20><>ȡ int <20><>ɫ
config.borderColor = (COLORREF)std::stoll(sBorderCol); // <20><>ȡ int <20><>ɫ
config.value = std::stod(sValue);
config.x = std::stod(sX); // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
config.y = std::stod(sY); // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
samples.push_back(config);
// <20><><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ Z ֵ<><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ʾ<EFBFBD>ı<EFBFBD>
std::string faciesName;
faciesName = name + "-" + sCode;
m_DepositionalMap.insert({ faciesName, config.value });
m_ColorList.insert({ config.value , config.fillColor });
}
return samples;
}
std::vector<Sample> KEDAlgorithm::ReadSamplesCSV(const CString& csvFile,
std::map<std::string, int>& labelMap)
{
std::vector<Sample> samples;
std::ifstream file(csvFile);
if (!file.is_open()) throw std::runtime_error("<EFBFBD>޷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>: " + csvFile);
std::string line;
std::getline(file, line); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ
while (std::getline(file, line)) {
std::stringstream ss(line);
std::string sx, sy, sz;
if (!std::getline(ss, sx, ',')) continue;
if (!std::getline(ss, sy, ',')) continue;
if (!std::getline(ss, sz, ',')) continue;
if (sx.empty() || sy.empty()) continue;
double x = std::stod(sx);
double y = std::stod(sy);
if (labelMap.find(sz) == labelMap.end()) {
int newId = static_cast<int>(labelMap.size());
labelMap[sz] = newId;
}
m_DepositionalMap.insert({ sz, labelMap[sz] });
samples.push_back({ x, y, labelMap[sz] });
}
return samples;
}
double KEDAlgorithm::KdeLogDensityBrute(const std::vector<FaciesConfig>& samples,
int label, double qx, double qy,
double bandwidth) const
{
if (samples.empty()) return -std::numeric_limits<double>::infinity();
double log_coeff = -std::log(2.0 * M_PI) - 2.0 * std::log(bandwidth);
double sum_exp = 0.0;
int n = 0;
for (const auto& s : samples) {
if (s.value != label) continue;
double dx = qx - s.x;
double dy = qy - s.y;
double dist2 = dx * dx + dy * dy;
double log_p = log_coeff - 0.5 * dist2 / (bandwidth * bandwidth);
sum_exp += std::exp(log_p);
++n;
}
if (n == 0) return -std::numeric_limits<double>::infinity();
return std::log(sum_exp / n);
}
bool KEDAlgorithm::WriteDSAAFromGrid(const std::string& output_grd,
const std::vector<float>& grid_data,
int nx, int ny,
double minx, double maxx,
double miny, double maxy)
{
if (static_cast<size_t>(nx * ny) != grid_data.size() || grid_data.empty())
return false;
float zmin = *std::min_element(grid_data.begin(), grid_data.end());
float zmax = *std::max_element(grid_data.begin(), grid_data.end());
std::ofstream out(output_grd);
if (!out.is_open()) return false;
out << "DSAA\n";
out << nx << " " << ny << "\n";
out << minx << " " << maxx << "\n";
out << miny << " " << maxy << "\n";
out << zmin << " " << zmax << "\n";
for (int j = 0; j < ny; ++j) {
int src_row = ny - 1 - j;
for (int i = 0; i < nx; ++i) {
size_t index = static_cast<size_t>(src_row) * nx + i;
out << grid_data[index] << " ";
if ((i + 1) % 10 == 0) out << "\n";
}
out << "\n";
}
return true;
}
bool KEDAlgorithm::GrdToKEVFile(const CString &gridFile, const CString &outputFile,
std::vector<CCurve*> pCurves, CColorBase &base)
{
std::shared_ptr<CXy> pXy = std::make_shared<CXy>();
pXy->FromGridAuto(gridFile);
CLayer* pLayer = pXy->FindAddLayer("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
CPositionList pointList;
int index = pXy->GetElement(DOUBLEFOX_MESH, pointList);
if (pointList.GetSize() == 0)
{
return false;
}
COne* pNewOne = pXy->GetAt(pointList.GetHead());
pNewOne->SetLayer(pLayer);
if (!CreateFaciesLines(pXy, pCurves))
{
return false;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
CArray<CColorItem, CColorItem> ColorList;
base.GetColor(ColorList);
if (ColorList.GetSize() > 0)
{
POSITION pt = pXy->FindFirstElement(DOUBLEFOX_MESH);
if (pt == nullptr)
{
return false;
}
COne* pOne1 = pXy->GetAt(pt);
CMesh* pMesh = (CMesh*)pOne1->GetValue();
pMesh->color.SetColor(ColorList);
pMesh->UpdateColorRuler();
}
pXy->SaveAsWithExtension(outputFile);
return true;
}
bool KEDAlgorithm::CreateFaciesLines(std::shared_ptr<CXy> pXy, std::vector<CCurve*> pCurves)
{
CString strLayerMark = _T("Layer:\\<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\\<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
CLayer* pLayer = pXy->FindAddLayer(strLayerMark);
AddFaciesCurves(pXy, pCurves, strLayerMark);
return true;
}
void KEDAlgorithm::AddFaciesCurves(std::shared_ptr<CXy> pXy, std::vector<CCurve*> curves, CString layerName)
{
for (size_t i = 0; i < curves.size(); i++)
{
CCurve* pCurve = curves.at(i);
if (pCurve == NULL) continue;
CCurveEx* ce = new CCurveEx(pCurve->num);
for (int i = 0; i < ce->num; i++)
{
ce->x[i] = pCurve->x[i];
ce->y[i] = pCurve->y[i];
ce->z[i] = pCurve->z[i];
}
ce->nPoint = pCurve->nPoint;
ce->GetLocation();
POSITION pos = NULL;
if (pCurve->name)
ce->SetName(pCurve->name);
pos = pXy->AddElement(ce, DOUBLEFOX_CURVE);
pXy->SetElementLayer(pos, layerName);
}
}
bool KEDAlgorithm::KEDMeshAlgorithm(const CString& csvFile, const CString& kevFile,
double grid_interval, double bandwidth, double beta, int anchor_radius,
std::function<void(int completed, int total)> progressCallback)
{
const int TOTAL_STEPS = 6;
auto reportProgress = [&](int step, bool failed = false) {
if (progressCallback) {
progressCallback(failed ? -1 : step, TOTAL_STEPS);
}
};
m_cancelRequested.store(false);
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
std::map<std::string, int> labelMap;
auto samples = LoadFaciesSettings(csvFile, labelMap);
if (samples.empty()) {
reportProgress(0, true);
return false;
}
reportProgress(1);
int num_classes = static_cast<int>(labelMap.size());
if (num_classes == 0) {
reportProgress(1, true);
return false;
}
// <20><>Χ
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
for (const auto& s : samples)
{
minx = std::min(minx, s.x);
maxx = std::max(maxx, s.x);
miny = std::min(miny, s.y);
maxy = std::max(maxy, s.y);
}
int nx = static_cast<int>((maxx - minx) / grid_interval) + 1;
int ny = static_cast<int>((maxy - miny) / grid_interval) + 1;
std::cout << "Grid nx=" << nx << " ny=" << ny << std::endl;
// <20><><EFBFBD><EFBFBD>ͼ
std::vector<cv::Mat> probMaps;
probMaps.reserve(num_classes);
for (int c = 0; c < num_classes; ++c)
probMaps.emplace_back(cv::Mat::zeros(ny, nx, CV_32F));
// KDE + <20><><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>
#pragma omp parallel
{
std::vector<double> log_densities(num_classes);
#pragma omp for collapse(2) schedule(dynamic)
for (int iy = 0; iy < ny; ++iy)
{
if (m_cancelRequested.load()) continue;
for (int ix = 0; ix < nx; ++ix)
{
double gx = minx + ix * grid_interval;
double gy = maxy - iy * grid_interval;
for (int c = 0; c < num_classes; ++c)
log_densities[c] = KdeLogDensityBrute(samples, c, gx, gy, bandwidth);
double max_log = *std::max_element(log_densities.begin(), log_densities.end());
if (max_log <= -1e20)
{
for (int c = 0; c < num_classes; ++c)
probMaps[c].at<float>(iy, ix) = 1.0f / num_classes;
}
else
{
double sum_exp = 0.0;
for (int c = 0; c < num_classes; ++c)
if (log_densities[c] > -1e20)
sum_exp += std::exp(log_densities[c] - max_log);
for (int c = 0; c < num_classes; ++c)
{
double p = 0.0;
if (log_densities[c] > -1e20)
p = std::exp(log_densities[c] - max_log) / sum_exp;
p = (1.0 - beta) * p + beta * (1.0 / num_classes);
probMaps[c].at<float>(iy, ix) = static_cast<float>(p);
}
}
}
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(2);
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
cv::Mat initialGrid(ny, nx, CV_8UC1, cv::Scalar(0));
for (int iy = 0; iy < ny; ++iy)
{
for (int ix = 0; ix < nx; ++ix)
{
int best_label = 0;
float best_prob = probMaps[0].at<float>(iy, ix);
for (int c = 1; c < num_classes; ++c)
{
float p = probMaps[c].at<float>(iy, ix);
if (p > best_prob) { best_prob = p; best_label = c; }
}
initialGrid.at<uchar>(iy, ix) = static_cast<uchar>(best_label);
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(3);
// <20><>̬ѧ<CCAC><D1A7><EFBFBD><EFBFBD>
cv::Mat tempGrid = initialGrid.clone();
cv::morphologyEx(tempGrid, tempGrid, cv::MORPH_OPEN,
cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
cv::morphologyEx(tempGrid, tempGrid, cv::MORPH_CLOSE,
cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(9, 9)));
cv::Mat finalGrid = tempGrid.clone();
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(4);
// ê<><C3AA><EFBFBD>ӹ<EFBFBD>
for (const auto& s : samples)
{
int col = static_cast<int>(std::round((s.x - minx) / grid_interval));
int row = static_cast<int>(std::round((maxy - s.y) / grid_interval));
if (col >= 0 && col < finalGrid.cols &&
row >= 0 && row < finalGrid.rows)
{
cv::circle(finalGrid, cv::Point(col, row), anchor_radius,
cv::Scalar(s.value), -1);
}
}
CSplitPath sp;
sp.SetModuleFileName();
CString xmlPath = "";
xmlPath.Format("%s%s", sp.GetPath(), "facies");
sp.MakeDirectory(xmlPath);
CString gridFile = "";
gridFile.Format("%s%s", xmlPath, "\\facies.grd");
// <20><><EFBFBD><EFBFBD> GRD
std::vector<float> grid_data;
grid_data.reserve(finalGrid.total());
for (int i = 0; i < finalGrid.rows; ++i)
for (int j = 0; j < finalGrid.cols; ++j)
grid_data.push_back(static_cast<float>(finalGrid.at<uchar>(i, j)));
if (!WriteDSAAFromGrid(std::string(gridFile), grid_data,
finalGrid.cols, finalGrid.rows,
minx, maxx, miny, maxy))
{
reportProgress(5, true);
return false;
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(5);
CArray<CColorItem, CColorItem> ColorList;
CColorBase base;
base.Clear();
for (const auto& pair : m_ColorList)
{
CColorItem colorMesh;
colorMesh.SetColor(pair.second);
colorMesh.z = pair.first;
colorMesh.m_bContinue = true;
ColorList.Add(colorMesh);
}
base.SetColor(ColorList);
ProcessExistingGrd(gridFile, kevFile, base, true, progressCallback);
reportProgress(6);
return true;
}
bool KEDAlgorithm::IDWMeshAlgorithm(const CString& csvFile,
const CString& kevFile,
const CString& boundaryFile,
double grid_interval,
int subblock_count,
int idw_neighbors,
double idw_power,
bool use_shepard,
bool smooth_boundary,
bool isFaciesBorder,
std::function<void(int completed, int total)> progressCallback)
{
const int TOTAL_STEPS = 6;
auto reportProgress = [&](int step, bool failed = false) {
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
};
m_cancelRequested.store(false);
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::map<std::string, int> labelMap;
auto samples = LoadFaciesSettings(csvFile, labelMap);
if (samples.empty()) { reportProgress(0, true); return false; }
int num_classes = static_cast<int>(labelMap.size());
reportProgress(1);
//<2F><><EFBFBD>Χ<E3B7B6><CEA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
float sample_zmin = std::numeric_limits<float>::max();
float sample_zmax = std::numeric_limits<float>::lowest();
for (const auto& s : samples)
{
minx = std::min(minx, s.x);
maxx = std::max(maxx, s.x);
miny = std::min(miny, s.y);
maxy = std::max(maxy, s.y);
sample_zmin = std::min(sample_zmin, static_cast<float>(s.value));
sample_zmax = std::max(sample_zmax, static_cast<float>(s.value));
}
reportProgress(2);
//<2F><>ȡ<EFBFBD>߽<EFBFBD><DFBD>ļ<EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9><EFBFBD>)
std::vector<CCurveEx*> vBorder;
if (!boundaryFile.IsEmpty())
{
vBorder = GetDFDBorder(boundaryFile);
}
bool use_custom_border = !vBorder.empty();
//<2F><>չ<EFBFBD><D5B9>Χ
minx -= grid_interval;
miny -= grid_interval;
maxx += grid_interval;
maxy += grid_interval;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + KDTree
int nx = static_cast<int>((maxx - minx) / grid_interval) + 1;
int ny = static_cast<int>((maxy - miny) / grid_interval) + 1;
const float NO_DATA_VALUE = 1e301;
std::vector<float> grid_data(nx * ny, NO_DATA_VALUE);
PointCloud cloud; cloud.pts = samples;
typedef KDTreeSingleIndexAdaptor<
L2_Simple_Adaptor<double, PointCloud>,
PointCloud, 2> my_kd_tree_t;
my_kd_tree_t index(2, cloud, KDTreeSingleIndexAdaptorParams(10));
index.buildIndex();
reportProgress(3);
// ================= <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3> =================
std::vector<int> uniqueValues;
std::map<int, int> valueToIndex;
int vIdx = 0;
for (const auto& pair : m_ColorList) {
uniqueValues.push_back(pair.first); // <20><EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
valueToIndex[pair.first] = vIdx++; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ -> <20><><EFBFBD><EFBFBD><EFBFBD>±<EFBFBD> (0, 1, 2...)
}
// ȷ<><C8B7> num_classes <20><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>Сһ<D0A1><D2BB>
num_classes = static_cast<int>(uniqueValues.size());
// ==================================================================
// <20>ֿ鲢<D6BF><E9B2A2> IDW <20><>ֵ
int block_h = ny / subblock_count;
std::atomic<int> completed_rows{ 0 };
int total_rows = ny;
#pragma omp parallel for schedule(dynamic)
for (int by = 0; by < subblock_count; ++by)
{
int startY = by * block_h;
int endY = (by == subblock_count - 1) ? ny : (by + 1) * block_h;
std::vector<size_t> ret_indexes(idw_neighbors);
std::vector<double> out_dists_sqr(idw_neighbors);
std::vector<double> class_weights_local(num_classes);
for (int iy = startY; iy < endY; ++iy)
{
if (m_cancelRequested.load()) break;
for (int ix = 0; ix < nx; ++ix)
{
double qx = minx + ix * grid_interval;
double qy = maxy - iy * grid_interval;
// <20>߽<EFBFBD><DFBD><EFBFBD><EFBFBD><EFBFBD>
if (use_custom_border && !IsPointInPolygon(qx, qy, vBorder))
continue;
double query_pt[2] = { qx, qy };
nanoflann::KNNResultSet<double> resultSet(idw_neighbors);
resultSet.init(&ret_indexes[0], &out_dists_sqr[0]);
index.findNeighbors(resultSet, &query_pt[0]);
std::fill(class_weights_local.begin(), class_weights_local.end(), 0.0);
double R = sqrt(out_dists_sqr.back()) + 1e-9;
for (int k = 0; k < idw_neighbors; ++k)
{
double d = sqrt(out_dists_sqr[k]) + 1e-9;
double w = 0.0;
if (use_shepard)
{
w = pow((R - d) / (R * d + 1e-9), 2);
}
else
{
if (idw_power == 2.0)
{
w = 1.0 / (d * d);
}
else {
w = 1.0 / pow(d, idw_power);
}
}
int phys_value = cloud.pts[ret_indexes[k]].value;
int safe_index = valueToIndex[phys_value];
class_weights_local[safe_index] += w;
}
int best_idx = 0;
double best_w = -1.0;
for (int lbl = 0; lbl < num_classes; ++lbl)
{
if (class_weights_local[lbl] > best_w)
{
best_idx = lbl;
best_w = class_weights_local[lbl];
}
}
grid_data[iy * nx + ix] = static_cast<float>(uniqueValues[best_idx]);
}
//<2F><>̬<EFBFBD>н<EFBFBD><D0BD>Ȼش<C8BB>
int done = ++completed_rows;
if (progressCallback && (done % (ny / 100) == 0))
{
// ÿԼ1%<25><><EFBFBD><EFBFBD>
int percent = static_cast<int>((done * 100.0) / total_rows);
progressCallback(percent, 100); // ʵʱ<CAB5>ٷֱ<D9B7>ģʽ
}
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(4);
qDeleteAll(vBorder);
// д<><D0B4> GRD (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Чֵ<D0A7><D6B5><EFBFBD><EFBFBD>z<EFBFBD><7A>Χ)
CSplitPath sp;
sp.SetModuleFileName();
CString xmlPath;
xmlPath.Format("%s%s", sp.GetPath(), "facies");
sp.MakeDirectory(xmlPath);
CString gridFile;
gridFile.Format("%s%s", xmlPath, "\\facies_idw.grd");
WriteDSAAFromGridKeepZRange(
std::string(CT2A(gridFile)),
grid_data, nx, ny,
minx, maxx, miny, maxy,
sample_zmin, sample_zmax);
reportProgress(5);
CArray<CColorItem, CColorItem> ColorList;
CColorBase base;
base.Clear();
for (const auto& pair : m_ColorList)
{
CColorItem colorMesh;
colorMesh.SetColor(pair.second);
colorMesh.z = pair.first;
colorMesh.m_bContinue = true;
ColorList.Add(colorMesh);
}
base.SetColor(ColorList);
//<2F><><EFBFBD><EFBFBD> KEV
ProcessExistingGrd(gridFile, kevFile, base, isFaciesBorder, progressCallback);
reportProgress(6);
return true;
}
void KEDAlgorithm::StopTask()
{
m_cancelRequested.store(true);
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD> + <20><><EFBFBD><EFBFBD> + ȥë<C8A5>̣<EFBFBD>
void KEDAlgorithm::PostProcessFaciesBoundaries(
std::vector<CCurve*>& pCurves,
double sigma_smooth,
int min_seg_cells,
double drop_closed_thresh,
double dx, double dy)
{
std::vector<CCurve*> filtered;
filtered.reserve(pCurves.size());
for (auto* curve : pCurves)
{
if (!curve || curve->num < 3) continue;
//ȥ<><C8A5>̫<EFBFBD><CCAB><EFBFBD>߶<EFBFBD>
double totalLen = 0.0;
for (int i = 1; i < curve->num; ++i)
{
double dx_ = curve->x[i] - curve->x[i - 1];
double dy_ = curve->y[i] - curve->y[i - 1];
totalLen += std::sqrt(dx_ * dx_ + dy_ * dy_);
}
if (totalLen < min_seg_cells * std::min(dx, dy))
{
delete curve;
continue;
}
// <20><>˹ƽ<CBB9><C6BD><EFBFBD>ߣ<EFBFBD><DFA3><EFBFBD><EFBFBD>β<EFBFBD><CEB2>
if (sigma_smooth > 0.1)
{
std::vector<double> newX(curve->num), newY(curve->num);
int r = static_cast<int>(sigma_smooth * 2.0);
double sigma2 = sigma_smooth * sigma_smooth;
for (int i = 0; i < curve->num; ++i)
{
double sumW = 0.0, sumX = 0.0, sumY = 0.0;
for (int j = std::max(0, i - r); j < std::min(curve->num, i + r + 1); ++j)
{
double w = std::exp(-0.5 * (std::pow(i - j, 2) / sigma2));
sumW += w;
sumX += w * curve->x[j];
sumY += w * curve->y[j];
}
newX[i] = sumX / sumW;
newY[i] = sumY / sumW;
}
for (int i = 0; i < curve->num; ++i)
{
curve->x[i] = newX[i];
curve->y[i] = newY[i];
}
}
filtered.push_back(curve);
}
pCurves.swap(filtered);
}
std::vector<CCurveEx*> KEDAlgorithm::GetDFDBorder(const CString& path)
{
CString borderFile = path;
if (!CFindFileEx::IsFileExists(borderFile)) {
return {};
}
std::shared_ptr<CXy> pXy = std::make_shared<CXy>();
borderFile = borderFile.Trim();
if (borderFile.GetLength() <= 0 || borderFile == "NULL") {
return {};
}
if (!pXy->ReadWithExtension(borderFile)) {
return {};
}
std::vector<CCurveEx*> result;
CPtrList* pl = pXy->GetValueList();
for (POSITION pos = pl->GetHeadPosition(); pos != nullptr; pl->GetNext(pos)) {
COne* pOne = (COne*)pl->GetAt(pos);
if (pOne->GetType() == DOUBLEFOX_CURVE) {
CCurveEx* pCurve = (CCurveEx*)(pOne->GetValue());
CCurveEx* pCurveNew = new CCurveEx();
*pCurveNew = *pCurve;
result.push_back(pCurveNew);
}
}
return result;
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϵ<EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param qx <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> X <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param qy <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Y <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD>򷵻<EFBFBD> true<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򷵻<EFBFBD> false
*/
bool KEDAlgorithm::IsPointInPolygon(double qx, double qy, const std::vector<CCurveEx*>& polygons)
{
// <20><><EFBFBD><EFBFBD>û<EFBFBD>б߽磬<DFBD><E7A3AC><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ڱ߽<DAB1><DFBD><EFBFBD>
if (polygons.empty()) return true;
for (const auto* poly : polygons) {
if (!poly || poly->num < 3) continue;
int crossings = 0;
int num_vertices = poly->num;
// <20><><EFBFBD><EFBFBD><EFBFBD>պ϶<D5BA><CFB6><EFBFBD><EFBFBD>Σ<EFBFBD><CEA3><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>
if (poly->x[0] == poly->x[num_vertices - 1] && poly->y[0] == poly->y[num_vertices - 1]) {
num_vertices--;
}
for (int i = 0, j = num_vertices - 1; i < num_vertices; j = i++) {
double xi = poly->x[i], yi = poly->y[i];
double xj = poly->x[j], yj = poly->y[j];
// <20><><EFBFBD>߷<EFBFBD><DFB7><EFBFBD><EFBFBD><EFBFBD> qx <20><><EFBFBD><EFBFBD> X <20><><EFBFBD>򷢳<EFBFBD><F2B7A2B3><EFBFBD><EFBFBD>ߣ<EFBFBD>ͳ<EFBFBD><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>αߵĽ<DFB5><C4BD><EFBFBD><EFBFBD><EFBFBD>
if (((yi > qy) != (yj > qy)) && // <20>߶ο<DFB6>Խˮƽ<CBAE><C6BD> y=qy
(qx < (xj - xi) * (qy - yi) / (yj - yi) + xi)) // <20><><EFBFBD><EFBFBD><E9BDBB><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD> qx <20>Ҳ<EFBFBD>
{
crossings++;
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>
if (crossings % 2 == 1) return true;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD>ζ<EFBFBD><CEB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>
return false;
}
bool KEDAlgorithm::WriteDSAAFromGridKeepZRange(const std::string& output_grd, const std::vector<float>& grid_data,
int nx, int ny, double minx, double maxx, double miny, double maxy, float zmin, float zmax)
{
if (static_cast<size_t>(nx * ny) != grid_data.size() || grid_data.empty())
return false;
std::ofstream out(output_grd);
if (!out.is_open()) return false;
out << "DSAA\n";
out << nx << " " << ny << "\n";
out << minx << " " << maxx << "\n";
out << miny << " " << maxy << "\n";
out << zmin << " " << zmax << "\n";
for (int j = 0; j < ny; ++j) {
int src_row = ny - 1 - j;
for (int i = 0; i < nx; ++i) {
size_t index = static_cast<size_t>(src_row) * nx + i;
out << grid_data[index] << " ";
if ((i + 1) % 10 == 0) out << "\n";
}
out << "\n";
}
return true;
}
std::unordered_map<std::string, int> KEDAlgorithm::GetDepositionalMap()
{
return m_DepositionalMap;
}
bool KEDAlgorithm::NNMeshAlgorithm(const CString& csvFile,
const CString& kevFile,
const CString& boundaryFile,
double grid_interval,
double sigma,
int open_iter,
int close_iter,
bool isFaciesBorder,
std::function<void(int completed, int total)> progressCallback)
{
const int TOTAL_STEPS = 6;
auto reportProgress = [&](int step, bool failed = false) {
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
};
m_cancelRequested.store(false);
std::map<std::string, int> labelMap;
auto samples = LoadFaciesSettings(csvFile, labelMap);
if (samples.empty()) { reportProgress(0, true); return false; }
int num_classes = static_cast<int>(labelMap.size());
reportProgress(1);
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
float sample_zmin = std::numeric_limits<float>::max();
float sample_zmax = std::numeric_limits<float>::lowest();
for (const auto& s : samples) {
minx = std::min(minx, s.x); maxx = std::max(maxx, s.x);
miny = std::min(miny, s.y); maxy = std::max(maxy, s.y);
sample_zmin = std::min(sample_zmin, (float)s.value);
sample_zmax = std::max(sample_zmax, (float)s.value);
}
// Python: np.arange(start, stop + step*0.1, step)
// <20><>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
int nx = static_cast<int>(std::floor((maxx - minx + grid_interval * 0.01) / grid_interval)) + 1;
int ny = static_cast<int>(std::floor((maxy - miny + grid_interval * 0.01) / grid_interval)) + 1;
std::vector<CCurveEx*> vBorder;
if (!boundaryFile.IsEmpty())
{
vBorder = GetDFDBorder(boundaryFile);
}
bool use_custom_border = !vBorder.empty();
PointCloud cloud; cloud.pts = samples;
typedef KDTreeSingleIndexAdaptor<L2_Simple_Adaptor<double, PointCloud>, PointCloud, 2> my_kd_tree_t;
my_kd_tree_t index(2, cloud, KDTreeSingleIndexAdaptorParams(10));
index.buildIndex();
reportProgress(2);
// <20><><EFBFBD>ɳ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD> (Label<65><6C><EFBFBD><EFBFBD>ͼ)
cv::Mat gridMat(ny, nx, CV_32SC1);
#pragma omp parallel for
for (int iy = 0; iy < ny; ++iy) {
if (m_cancelRequested.load()) continue;
for (int ix = 0; ix < nx; ++ix) {
double qx = minx + ix * grid_interval;
double qy = maxy - iy * grid_interval; // ע<><D7A2>Y<EFBFBD><EFBFBD><E1B7BD>ͨ<EFBFBD><CDA8><EFBFBD>Ƿ<EFBFBD><C7B7>ģ<EFBFBD><C4A3><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դϰ<D4B4><CFB0>
double query_pt[2] = { qx, qy };
size_t ret_index;
double out_dist_sqr;
nanoflann::KNNResultSet<double> resultSet(1);
resultSet.init(&ret_index, &out_dist_sqr);
index.findNeighbors(resultSet, &query_pt[0]);
gridMat.at<int>(iy, ix) = cloud.pts[ret_index].value;
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(3);
// 1. <20><>ȡ<EFBFBD><C8A1><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ (std::map <20><><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
std::vector<int> uniqueValues;
for (const auto& pair : m_ColorList) {
uniqueValues.push_back(pair.first);
}
int actualNumClasses = static_cast<int>(uniqueValues.size());
// ================= <20><>˹<EFBFBD><CBB9><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD> =================
if (sigma > 0.1 && actualNumClasses > 0) {
std::vector<cv::Mat> probLayers(actualNumClasses);
for (int i = 0; i < actualNumClasses; ++i)
probLayers[i] = cv::Mat::zeros(ny, nx, CV_32F);
// One-Hot Encoding (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵӳ<D6B5>ƽ<E4B5BD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
#pragma omp parallel for
for (int y = 0; y < ny; ++y) {
for (int x = 0; x < nx; ++x) {
int currentVal = gridMat.at<int>(y, x);
// <20>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>Ӧ<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD>
for (int i = 0; i < actualNumClasses; ++i) {
if (uniqueValues[i] == currentVal) {
probLayers[i].at<float>(y, x) = 1.0f;
break;
}
}
}
}
// <20>˴<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>
int radius = static_cast<int>(4.0 * sigma + 0.5);
int ksize = 2 * radius + 1;
#pragma omp parallel for
for (int i = 0; i < actualNumClasses; ++i) {
cv::GaussianBlur(probLayers[i], probLayers[i],
cv::Size(ksize, ksize),
sigma, sigma,
cv::BORDER_REFLECT);
}
// Argmax <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>߸<EFBFBD><DFB8>ʵIJ<CAB5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭΪ<D4AD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ)
#pragma omp parallel for
for (int y = 0; y < ny; ++y) {
for (int x = 0; x < nx; ++x) {
int best_idx = 0;
float max_prob = -1.0f;
for (int i = 0; i < actualNumClasses; ++i) {
float p = probLayers[i].at<float>(y, x);
if (p > max_prob) {
max_prob = p;
best_idx = i;
}
}
// <20><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ֵ
gridMat.at<int>(y, x) = uniqueValues[best_idx];
}
}
}
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
reportProgress(4);
// <20><>̬ѧ<CCAC><D1A7><EFBFBD><EFBFBD>
if (open_iter > 0 || close_iter > 0) {
// ʹ<><CAB9><EFBFBD><EFBFBD>Բ<EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı߽<C4B1><DFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD>
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
cv::Mat optimizedGrid = gridMat.clone();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0, 1, 2
for (int i = 0; i < actualNumClasses; ++i) {
int physValue = uniqueValues[i];
cv::Mat mask;
// Ѱ<><D1B0>ͼ<EFBFBD><CDBC><EFBFBD>е<EFBFBD><D0B5><EFBFBD> physValue <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
cv::inRange(gridMat, cv::Scalar(physValue), cv::Scalar(physValue), mask);
if (open_iter > 0)
cv::morphologyEx(mask, mask, cv::MORPH_OPEN, element, cv::Point(-1, -1), open_iter);
if (close_iter > 0)
cv::morphologyEx(mask, mask, cv::MORPH_CLOSE, element, cv::Point(-1, -1), close_iter);
// <20><>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɰ<EFBFBD><C9B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ȥ
optimizedGrid.setTo(cv::Scalar(physValue), mask);
}
gridMat = optimizedGrid;
}
reportProgress(5);
std::vector<float> grid_data;
grid_data.reserve(nx * ny);
for (int iy = 0; iy < ny; ++iy) {
for (int ix = 0; ix < nx; ++ix) {
double rx = minx + ix * grid_interval;
double ry = maxy - iy * grid_interval;
if (use_custom_border && !IsPointInPolygon(rx, ry, vBorder)) {
grid_data.push_back(1e301);
}
else {
grid_data.push_back((float)gridMat.at<int>(iy, ix));
}
}
}
qDeleteAll(vBorder);
CSplitPath sp;
sp.SetModuleFileName();
CString xmlPath;
xmlPath.Format("%s%s", sp.GetPath(), "facies");
sp.MakeDirectory(xmlPath);
CString gridPath;
gridPath.Format("%s%s", xmlPath, "\\facies_nn.grd");
WriteDSAAFromGridKeepZRange(
std::string(CT2A(gridPath)),
grid_data, nx, ny,
minx, maxx, miny, maxy,
sample_zmin, sample_zmax);
CArray<CColorItem, CColorItem> ColorList;
CColorBase base;
base.Clear();
for (const auto& pair : m_ColorList)
{
CColorItem colorMesh;
colorMesh.SetColor(pair.second);
colorMesh.z = pair.first;
colorMesh.m_bContinue = true;
ColorList.Add(colorMesh);
}
base.SetColor(ColorList);
ProcessExistingGrd(gridPath, kevFile, base, isFaciesBorder, progressCallback);
reportProgress(6);
return true;
}