10、基于osg引擎生成热力图高度图实现3D热力图可视化、3D热力图实时更新(带过渡效果)

news2025/3/19 23:38:16

1、结果
在这里插入图片描述
在这里插入图片描述
2、完整C++代码

#include <sstream>
#include <iomanip>
#include <iostream>
#include <vector>
#include <random>
#include <cmath>
#include <functional>
#include <osgViewer/viewer>
#include <osgDB/ReadFile>
#include <osg/Texture3D>
#include <osg/Texture1D>
#include <osgDB/FileUtils>
#include <osg/Billboard>
#include <osg/TexGenNode>
#include <osg/ClipNode>
#include <osgDB/WriteFile>
#include <osg/Point>
#include <osg/ShapeDrawable>
#include <osg/PositionAttitudeTransform>
#include <osg/MatrixTransform>
#include <osgGA/TrackballManipulator>
#include <osg/ComputeBoundsVisitor>
#include <osg/TransferFunction>
#include <array>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#include <osgUtil/SmoothingVisitor>
const std::string DATA_PATH = R"(..\data\)";
const std::string SHADER_PATH = R"(..\shaders\)";
const float RADIUS = 35;//设置热力点的影响半径
struct Point { int x, y; float value; };
// 生成随机数
int getRandomInt(int min, int max) {
    return min + std::rand() % (max - min + 1);
}

// 颜色插值(用于热力图渐变)
osg::Vec4 lerpColor(float value) {
    value = osg::clampBetween(value, 0.0f, 1.0f);  // 确保 value 在 [0, 1] 范围内

    osg::Vec4 colors[] = {
        osg::Vec4(49/255.0, 54/255.0, 149/255.0, value),
        osg::Vec4(69/255.0, 117/255.0, 180/255.0, value),
        osg::Vec4(116/255.0, 173/255.0, 209/255.0, value),
        osg::Vec4(171/255.0, 217/255.0, 233/255.0, value),
        osg::Vec4(224/255.0, 243/255.0, 248/255.0, value),
        osg::Vec4(255/255.0, 255/255.0, 191/255.0, value),
        osg::Vec4(254/255.0, 224/255.0, 144/255.0, value),
        osg::Vec4(253/255.0, 174/255.0, 97/255.0, value),
        osg::Vec4(244/255.0, 109/255.0, 67/255.0, value),
        osg::Vec4(215/255.0, 48/255.0, 39/255.0, value),
        osg::Vec4(165/255.0, 0.0, 38/255.0, value)
    };


    //osg::Vec4 colors[] = {
    //    osg::Vec4(50 / 255.0, 136 / 255.0, 189 / 255.0, value),   
    //    osg::Vec4(102 / 255.0, 194 / 255.0, 165 / 255.0, value),
    //    osg::Vec4(171 / 255.0, 221 / 255.0, 164 / 255.0, value),
    //    osg::Vec4(230 / 255.0, 245 / 255.0, 152 / 255.0, value),
    //    osg::Vec4(254 / 255.0, 224 / 255.0, 139 / 255.0, value),
    //    osg::Vec4(253 / 255.0, 174 / 255.0, 97 / 255.0, value),
    //    osg::Vec4(244 / 255.0, 109 / 255.0, 67 / 255.0, value),
    //    osg::Vec4(213 / 255.0, 62 / 255.0, 79 / 255.0, value),
    //};

    int numColors = sizeof(colors) / sizeof(colors[0]);

    float t = value * (numColors - 1);      // 乘以 (数量-1)
    int index = static_cast<int>(t);

    // 处理边界情况,避免越界
    if (index >= numColors - 1) {
        return colors[numColors - 1];       // 直接返回最后一个颜色
    }
    t -= index;// 提取 t 的小数部分,作为插值比例

    return colors[index] * (1 - t) + colors[index + 1] * t;
}

std::vector<Point> generateData(int width, int height, int pointCount)
{
    std::vector<Point> points;
    for (int i = 0; i < pointCount; ++i) {
        points.push_back({ getRandomInt(10, width - 10), getRandomInt(10, height - 10), getRandomInt(0, 100) / 100.0f });
    }
    return points;
}

// 生成热力图图像
osg::ref_ptr<osg::Image> generateHeatmap(int width, int height, std::vector<Point> points) {
    osg::ref_ptr<osg::Image> image = new osg::Image();
    image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);

    std::vector<unsigned char> buffer(width * height * 4, 0); // 初始化RGBA缓冲区

    // 绘制点 (模拟圆形模糊)
    for (const auto& p : points) {
        for (int dx = -RADIUS; dx <= RADIUS; ++dx) {
            for (int dy = -RADIUS; dy <= RADIUS; ++dy) {
                int px = p.x + dx;//计算当前像素的x坐标
                int py = p.y + dy;//计算当前像素的y坐标

                //确保当前像素点在图像范围内
                if (px >= 0 && px < width && py >= 0 && py < height) {
                    //计算该像素点与中心点的归一化距离
                    float dist = std::sqrt(dx * dx + dy * dy) / RADIUS;
                    //如果距离在热力点影响范围内
                    if (dist <= 1.0f) {
                        //计算当前像素在缓冲区中的索引
                        int index = (py * width + px) * 4;
                        //计算当前像素的影响强度
                        float intensity = (1.0f - dist) * p.value;
                        //叠加透明度
                        float oldAlpha = buffer[index + 3] / 255.0f; // 读取背景透明度(归一化到0~1)
                        float newAlpha = intensity + oldAlpha * (1.0f - intensity); // 计算混合透明度
                        buffer[index + 3] = static_cast<int>(std::min(255.0f, newAlpha * 255)); // 更新透明度
                    }
                }
            }
        }
    }

    // 颜色映射
    for (int i = 0; i < width * height; ++i) {
        float alpha = buffer[i * 4 + 3] / 255.0f; // 归一化透明度
        osg::Vec4 color = lerpColor(alpha);
        buffer[i * 4] = static_cast<unsigned char>(color.r() * 255);
        buffer[i * 4 + 1] = static_cast<unsigned char>(color.g() * 255);
        buffer[i * 4 + 2] = static_cast<unsigned char>(color.b() * 255);
        buffer[i * 4 + 3] = static_cast<unsigned char>(color.a() * 255);
    }

    // 复制数据到 osg::Image
    memcpy(image->data(), buffer.data(), buffer.size());
    return image;
}

// 生成高度图
osg::ref_ptr<osg::Image> generateHeightmap(int width, int height, std::vector<Point> points)
{
    osg::ref_ptr<osg::Image> image = new osg::Image;
    image->allocateImage(width, height, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE);

    std::vector<float> heightBuffer(width * height, 0.0);//浮点型高度缓存

    // 计算高度影响(使用高斯衰减)
    for (const auto& p : points)
    {
        for (int dx = -RADIUS; dx <= RADIUS; ++dx) {
            for (int dy = -RADIUS; dy <= RADIUS; ++dy) {
                int px = p.x + dx;
                int py = p.y + dy;
                if (px >= 0 && px < width && py >= 0 && py < height)
                {
                    float distance = std::sqrt(dx * dx + dy * dy);
                    if (distance <= RADIUS) {
                        float normalizedDist = distance / RADIUS;
                        //高斯衰减系数
                        float falloff = std::exp(-normalizedDist * normalizedDist * 4.0f);
                        int index = py * width + px;
                        heightBuffer[index] += falloff * p.value;
                    }
                }
            }
        }
    }

    // 归一化处理
    float maxHeight = *std::max_element(heightBuffer.begin(), heightBuffer.end());
    std::vector<unsigned char> grayBuffer(width * height);
    for (int i = 0; i < width * height; ++i)
    {
        float normalized = heightBuffer[i] / maxHeight;
        grayBuffer[i] = static_cast<unsigned char>(normalized * 255);
    }
    memcpy(image->data(), grayBuffer.data(), grayBuffer.size());
    return image;
}

void generateHeatmapTexture()
{
    std::vector<Point> data = generateData(1024, 1024, 100);
    osg::ref_ptr<osg::Image> heatmap2dImage = generateHeatmap(1024, 1024, data);
    osg::ref_ptr<osg::Image> heightmapImage = generateHeightmap(1024, 1024, data);
    // 使用OSG保存图像
    if (osgDB::writeImageFile(*heatmap2dImage, "heatmap2d.png")) {
        std::cout << "Image saved as " << "heatmap_osg.png" << std::endl;
    }
    else {
        std::cerr << "Error saving image." << std::endl;
    }

    if (osgDB::writeImageFile(*heightmapImage, "heightmap.png")) {
        std::cout << "Image saved as " << "heightmap.png" << std::endl;
    }
    else {
        std::cerr << "Error saving image." << std::endl;
    }
}

// 创建地形节点
osg::ref_ptr<osg::Node> createTerrain(osg::Image* heightmap, osg::Image* heatmap) {
    // 创建几何体
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
    osg::ref_ptr<osg::Geode> geode = new osg::Geode();
    geode->addDrawable(geometry);

    // 创建顶点数组
    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
    const int width = heightmap->s();
    const int height = heightmap->t();
    const float terrainSize = 200.0f; // 地形物理尺寸
    const float heightScale = 50.0f;  // 高度缩放系数

    // 生成顶点数据
    unsigned char* heightData = heightmap->data();
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            // 计算顶点位置(居中)
            float xPos = (x - width / 2.0f) * (terrainSize / width);
            float yPos = (y - height / 2.0f) * (terrainSize / height);
            float zPos = heightData[y * width + x] / 255.0f * heightScale;

            vertices->push_back(osg::Vec3(xPos, yPos, zPos));
        }
    }

    // 创建索引数组(三角形带)
    osg::ref_ptr<osg::DrawElementsUShort> indices =
        new osg::DrawElementsUShort(GL_TRIANGLES);
    for (int y = 0; y < height - 1; ++y) {
        for (int x = 0; x < width - 1; ++x) {
            // 创建两个三角形组成四边形
            int i0 = y * width + x;
            int i1 = i0 + 1;
            int i2 = i0 + width;
            int i3 = i2 + 1;

            indices->push_back(i1);
            indices->push_back(i2);
            indices->push_back(i0);

            indices->push_back(i3);
            indices->push_back(i2);
            indices->push_back(i1);
        }
    }

    // 设置几何体数据
    geometry->setVertexArray(vertices);
    geometry->addPrimitiveSet(indices);

    // 自动生成法线
    osgUtil::SmoothingVisitor::smooth(*geometry);

    // 创建纹理坐标数组
    osg::ref_ptr<osg::Vec2Array> texCoords = new osg::Vec2Array();
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            // 归一化纹理坐标 [0,1]
            float u = static_cast<float>(x) / (width - 1);
            float v = static_cast<float>(y) / (height - 1);
            texCoords->push_back(osg::Vec2(u, v));
        }
    }
    geometry->setTexCoordArray(0, texCoords);

    // 应用纹理
    osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
    texture->setImage(heatmap);
    texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
    texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
    texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
    texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

    osg::StateSet* stateset = geode->getOrCreateStateSet();
    stateset->setTextureAttributeAndModes(0, texture);
    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
    stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
    return geode;
}

osg::Geode* createHeatmap3D() {
    const int GRID_SIZE = 256;
    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
    osg::ref_ptr<osg::Vec2Array> texCoords = new osg::Vec2Array;

    for (int y = 0; y < GRID_SIZE; ++y) {
        for (int x = 0; x < GRID_SIZE; ++x) {
            float u = x / (GRID_SIZE - 1.0f);
            float v = y / (GRID_SIZE - 1.0f);
            vertices->push_back(osg::Vec3(u * 100 - 50, v * 100 - 50, 0)); // 居中显示
            texCoords->push_back(osg::Vec2(u, v));
        }
    }

    // 创建索引
    osg::ref_ptr<osg::DrawElementsUInt> indices =
        new osg::DrawElementsUInt(GL_TRIANGLES);
    for (int y = 0; y < GRID_SIZE - 1; ++y) {
        for (int x = 0; x < GRID_SIZE - 1; ++x) {
            int i0 = y * GRID_SIZE + x;
            int i1 = i0 + 1;
            int i2 = i0 + GRID_SIZE;
            int i3 = i2 + 1;

            indices->push_back(i1);
            indices->push_back(i2);
            indices->push_back(i0);
            indices->push_back(i3);
            indices->push_back(i2);
            indices->push_back(i1);
        }
    }

    geom->setVertexArray(vertices);
    geom->setTexCoordArray(0, texCoords);
    geom->addPrimitiveSet(indices);

    osgUtil::SmoothingVisitor::smooth(*geom);

    osg::Geode* geode = new osg::Geode;
    geode->addDrawable(geom);
    return geode;
}

osg::Texture2D* createTexture(osg::Image* image) {
    osg::Texture2D* tex = new osg::Texture2D;
    tex->setImage(image);
    tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
    tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
    tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
    tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
    return tex;
}

void setupStateSet(osg::Geode* geode) {
    osg::StateSet* ss = geode->getOrCreateStateSet();

    // 混合设置
    ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
    ss->setMode(GL_BLEND, osg::StateAttribute::ON);


    std::vector<Point> data = generateData(256, 256, 100);
    osg::ref_ptr<osg::Image> heatmap2dImage1 = generateHeatmap(256, 256, data);
    osg::ref_ptr<osg::Image> heightmapImage1 = generateHeightmap(256, 256, data);

    struct Textures {
        osg::ref_ptr<osg::Texture2D> current;
        osg::ref_ptr<osg::Texture2D> next;
        float transition = 0.0f;
        bool updating = false;
    };
    Textures heightTex, heatmapTex;
    // 初始纹理
    heightTex.current = createTexture(heightmapImage1);
    heatmapTex.current = createTexture(heatmap2dImage1);
    data = generateData(256, 256, 200);
    osg::ref_ptr<osg::Image> heatmap2dImage2 = generateHeatmap(256, 256, data);
    osg::ref_ptr<osg::Image> heightmapImage2 = generateHeightmap(256, 256, data);
    heightTex.next = createTexture(heightmapImage2);
    heatmapTex.next = createTexture(heatmap2dImage2);

    osg::Program* program = new osg::Program;
    ss->setAttribute(program);
    program->addShader(osgDB::readRefShaderFile(osg::Shader::VERTEX, SHADER_PATH + R"(heatmap3d.vert)"));
    program->addShader(osgDB::readRefShaderFile(osg::Shader::FRAGMENT, SHADER_PATH + R"(heatmap3d.frag)"));
    ss->setAttributeAndModes(program);
    program->addBindAttribLocation("texCoord", osg::Drawable::TEXTURE_COORDS_0);
    // 绑定纹理单元
    ss->setTextureAttribute(0, heightTex.current);
    ss->setTextureAttribute(1, heightTex.next);
    ss->setTextureAttribute(2, heatmapTex.current);
    ss->setTextureAttribute(3, heatmapTex.next);

    // Uniform绑定
    ss->addUniform(new osg::Uniform("heightMap", 0));
    ss->addUniform(new osg::Uniform("nextHeightMap", 1));
    ss->addUniform(new osg::Uniform("heatmap", 2));
    ss->addUniform(new osg::Uniform("nextHeatmap", 3));
    ss->addUniform(new osg::Uniform("transitionProgress", 0.0f));
}


osg::Timer_t startTime;
bool startSimulate = false;
class KeyboardEventHandler : public osgGA::GUIEventHandler {
public:
    KeyboardEventHandler(){}

    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override {
        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
            switch (ea.getKey()) {
            case 't':  
                if (!startSimulate)
                {
                    startTime = osg::Timer::instance()->tick();
                    startSimulate = true;
                }
                return true;
            default:
                return false;
            }
        }
        return false;
    }

private:
};

class TimeUpdateCallback : public osg::NodeCallback
{
public:
    TimeUpdateCallback()  {}

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
    {
        if (startSimulate)
        {
            osg::StateSet* ss = node->getStateSet();
            if (ss)
            {
                float time = osg::Timer::instance()->delta_s(startTime, osg::Timer::instance()->tick()) / 3.0f;
                time = osg::clampBetween(time, 0.0f, 1.0f);
                if (time == 1.0)
                {
                    std::random_device rd;  // 用于获取随机种子
                    std::mt19937 gen(rd()); // 使用 Mersenne Twister 算法

                    // 定义一个分布范围 [100, 200]
                    std::uniform_int_distribution<> dis(100, 200);
                    std::vector<Point> data = generateData(256, 256, dis(gen));
                    osg::ref_ptr<osg::Image> heatmap2dImage = generateHeatmap(256, 256, data);
                    osg::ref_ptr<osg::Image> heightmapImage = generateHeightmap(256, 256, data);
                    ss->setTextureAttribute(0, ss->getTextureAttribute(1, osg::StateAttribute::TEXTURE));
                    ss->setTextureAttribute(1, createTexture(heightmapImage));
                    ss->setTextureAttribute(2, ss->getTextureAttribute(3, osg::StateAttribute::TEXTURE));
                    ss->setTextureAttribute(3, createTexture(heatmap2dImage));
                    ss->getUniform("transitionProgress")->set(0.0f);
                    startTime = osg::Timer::instance()->tick();
                }
                else
                    ss->getUniform("transitionProgress")->set(time);
            }
            traverse(node, nv);
        }
    }

};

int preview3DHeatmapWithAnimate()
{
    osg::Geode* geode = createHeatmap3D();
    setupStateSet(geode);
    geode->setUpdateCallback(new TimeUpdateCallback());

    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Group> group = new osg::Group;
    group->addChild(geode);

    viewer->setSceneData(group);
    viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
    viewer->addEventHandler(new osgViewer::StatsHandler());
    osg::ref_ptr<KeyboardEventHandler> keyboardHandler = new KeyboardEventHandler;
    viewer->addEventHandler(keyboardHandler);
    return viewer->run();
}

int preview3DHeatmap()
{
    std::vector<Point> data = generateData(256, 256, 100);
    osg::ref_ptr<osg::Image> heatmap2dImage = generateHeatmap(256, 256, data);
    osg::ref_ptr<osg::Image> heightmapImage = generateHeightmap(256, 256, data);
    osg::ref_ptr<osg::Node> node = createTerrain(heightmapImage, heatmap2dImage);


	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	osg::ref_ptr<osg::Group> group = new osg::Group;
    group->addChild(node);

	viewer->setSceneData(group);
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());
	return viewer->run();
}

int preview2DHeatmap() {
    std::vector<Point> data = generateData(256, 256, 100);
    osg::ref_ptr<osg::Image> heatmap2dImage = generateHeatmap(256, 256, data);

    // 创建带纹理的四边形几何体
    osg::ref_ptr<osg::Geometry> quad = osg::createTexturedQuadGeometry(
        osg::Vec3(-1.0f, -1.0f, 0.0f), // 左下角顶点
        osg::Vec3(2.0f, 0.0f, 0.0f),  // 宽度向量
        osg::Vec3(0.0f, 2.0f, 0.0f),  // 高度向量
        0.0f, 0.0f, 1.0f, 1.0f        // 纹理坐标 (左下角到右上角)
    );

    osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
    texture->setImage(heatmap2dImage);

    osg::ref_ptr<osg::StateSet> stateSet = quad->getOrCreateStateSet();
    stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);

    // 创建Geode并添加几何体
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable(quad);

    // 创建场景图根节点
    osg::ref_ptr<osg::Group> root = new osg::Group;
    root->addChild(geode);

    // 创建并设置Viewer
    osgViewer::Viewer viewer;
    viewer.setSceneData(root);
    return viewer.run();
}

int main()
{
    //return preview2DHeatmap();
    //return preview3DHeatmap();
    return preview3DHeatmapWithAnimate();
}

3、着色器代码

//heatmap3d.vert
#version 110
/* GLSL 1.10需要显式声明精度 (OpenGL ES要求) */
#ifdef GL_ES
precision highp  float;
#endif
/* 自定义 uniforms */
uniform sampler2D heightMap;
uniform sampler2D nextHeightMap;
uniform float transitionProgress;
attribute vec2 texCoord;
// 输入纹理坐标属性(对应几何体的第0层纹理)
varying vec2 vTexCoord;

void main() {
    float x = gl_Vertex.x;
    float y = gl_Vertex.y;
    
    vTexCoord = texCoord;
    
    // 使用 texture2D 代替 texture 函数
    float currentHeight = texture2D(heightMap, texCoord.xy).r * 50.0;
    float nextHeight = texture2D(nextHeightMap, texCoord.xy).r * 50.0;
    
    // 高度插值计算
    float finalHeight = mix(currentHeight, nextHeight, transitionProgress);
    
    // 坐标变换
    vec4 pos = vec4(x, y, finalHeight, 1.0);
    gl_Position = gl_ModelViewProjectionMatrix * pos;
}
//heatmap3d.frag
#version 110
/* GLSL 1.10需要显式声明精度 (OpenGL ES要求) */
#ifdef GL_ES
precision mediump float;
#endif

uniform sampler2D heatmap;
uniform sampler2D nextHeatmap;
uniform float transitionProgress;
varying vec2 vTexCoord;

void main() {
    // 使用texture2D替代texture函数
    vec4 currentColor = texture2D(heatmap, vTexCoord);
    vec4 nextColor = texture2D(nextHeatmap, vTexCoord);
    
    // 使用gl_FragColor替代自定义输出
    gl_FragColor = mix(currentColor, nextColor, transitionProgress);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2318034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Modbus通信协议基础知识总结

1. 数据类型与存储区分类 Modbus协议将数据分为四类存储区&#xff0c;通过存储区代号区分&#xff1a; 输出线圈&#xff08;0x&#xff09;&#xff1a;可读写&#xff0c;对应二进制开关量&#xff08;如继电器状态&#xff09;&#xff0c;地址范围000001-065536&#xff…

AndroidStudio下载安装,环境部署以及常见问题解决教程(亲测)

AndroidStudio下载安装&#xff0c;环境部署以及常见问题解决&#xff01;&#xff01;&#xff01; 文章目录 前言 一、Android Studio 下载与安装 1.1 系统要求 1.2 下载 Android Studio 1.3 安装 Android Studio Windows 系统 1.4 初始配置 二、环境部署 2.1 安装 …

开源免费一句话生成儿童故事视频核心思想解析

再看一个演示视频&#xff0c;学会核心思想后&#xff0c;可以打造自己的内容生成工具&#xff0c;后文有基于飞书多维表格的实现效果&#xff1a; 一句话灵感生成儿童故事视频演示 这是一款专门为内容素材创作打造的创新工具&#xff0c;可根据用户输入的主题&#xff0c;快速…

数据结构——最短路(BFS,Dijkstra,Floyd)

完整版可以看我的最短路问题模版总结_稠密图最短路-CSDN博客 考研数据结构只考BFS,Dijkstra和Floyd 下面代码以Acwing模板题为例 BFS代码 适用类型&#xff1a; 1.单源最短路径 2.无权图 3.不适用于带权图和负权回路图 //Acwing走迷宫bfs #include<bits/stdc.h>usi…

Kali Linux汉化教程:轻松设置中文界面

1.打开终端 2.输入sudo dpkg-reconfigure locales&#xff0c;回车&#xff0c;输入密码&#xff0c;回车 sudo dpkg-reconfigure locales 3.往下滑&#xff0c;滑到底&#xff0c;找到‘zh_CN.UTF-8 UTF-8’,回车 4.选择‘zh_CN.UTF-8’,回车 5.没有 ‘zh_CN.UTF-8’选项的特…

C++和标准库速成(八)——指针、动态数组、const、constexpr和consteval

目录 1. 指针和动态数组1.1 栈和自由存储区1.2 使用指针1.3 动态分配的数组1.4 空指针常量 2. const2.1 const修饰类型2.2 const与指针2.3 使用const保护参数2.4 const方法(建议&#xff09; 3. constexpr4. consteval参考 1. 指针和动态数组 动态内存允许所创建的程序具有在编…

超声重建,3D重建 超声三维重建,三维可视化平台 UR 3D Reconstruction

1. 超声波3D重建技术的实现方法与算法 技术概述 3D超声重建是一种基于2D超声图像生成3D体积数据的技术&#xff0c;广泛应用于医学影像领域。通过重建和可视化三维结构&#xff0c;3D超声能够显著提高诊断精度和效率&#xff0c;同时减少医生的脑力负担。本技术文档将详细阐述…

[HelloCTF]PHPinclude-labs超详细WP-Level 6Level 7Level 8Level 9-php://协议

由于Level 6-9 关的原理都是通用的, 这里就拿第6关举例, 其他的关卡同理 源码分析 定位到代码 isset($_GET[wrappers]) ? include("php://".$_GET[wrappers]) : ; 与前几关发生变化的就是 php:// 解题分析 这一关要求我们使用 php协议 php:// 协议 php://filte…

【Linux】Bash是什么?怎么使用?

李升伟 整理 什么是 Bash&#xff1f; Bash&#xff08;Bourne Again Shell&#xff09;是一种 命令行解释器&#xff08;Shell&#xff09;&#xff0c;广泛用于 Unix 和 Linux 操作系统。它是 Bourne Shell&#xff08;sh&#xff09; 的增强版&#xff0c;提供了更多的功能…

如何创建并保存HTML文件?零基础入门教程

原文&#xff1a;如何创建并保存HTML文件&#xff1f;零基础入门教程 | w3cschool笔记 本文将以Windows系统为例&#xff0c;教你用最简单的记事本创建并保存第一个HTML网页。 &#x1f4dd; 第一步&#xff1a;准备工具 文本编辑器&#xff1a;使用系统自带的记事本&#xff…

React19源码系列之FiberRoot节点和Fiber节点

在上一篇文章&#xff0c;看了createRoot函数的大致流程。 createContainer函数创建并返回了FiberRoot 。FiberRoot是由createFiberRoot函数创建&#xff0c; createFiberRoot函数还将 FiberRoot和 根Fiber 通过current属性建立起了联系。将FiberRoot作为参数传给 ReactDOMRoo…

TCP协议的多线程应用、多线程下的网络编程

DAY13.2 Java核心基础 多线程下的网络编程 基于单点连接的方式&#xff0c;一个服务端对应一个客户端&#xff0c;实际运行环境中是一个服务端需要对应多个客户端 创建ServerSocketNable类&#xff0c;多线程接收socket对象 public class ServerSocketNable implements Run…

华为中小型企业项目案例

实验目的(1) 熟悉华为交换机和路由器的应用场景 (2) 掌握华为交换机和路由器的配置方法 实验拓扑实验拓扑如图所示。 华为中小型企业项目案例拓扑图 实验配置市场部和技术部的配置创建VLANLSW1的配置 [LSW1]vlan batch 10 20 [LSW1]q…

LabVIEW VI Scripting随机数波形图自动生成

通过LabVIEW VI Scripting 技术&#xff0c;实现从零开始编程化创建并运行一个随机数波形监测VI。核心功能包括自动化生成VI框架、添加控件与函数、配置数据流逻辑及界面布局优化&#xff0c;适用于批量生成测试工具、教学模板开发或复杂系统的模块化构建。通过脚本化操作&…

MATLAB 控制系统设计与仿真 - 26

状态空间控制系统概述 状态空间描述 现代控制理论是建立在状态空间基础上的控制系统分析和设计理论&#xff0c;它用状态变量来刻画系统的内部特征&#xff0c;用‘一节微分方程组’来描述系统的动态特性。系统的状态空间模型描述了系统输入/输出与内部状态之间的关系&#x…

Python----计算机视觉处理(Opencv:图像镜像旋转)

一、图像镜像旋转 图像的旋转是围绕一个特定点进行的&#xff0c;而图像的镜像旋转则是围绕坐标轴进行的。图像镜像旋转&#xff0c;也可 以叫做图像翻转&#xff0c;分为水平翻转、垂直翻转、水平垂直翻转三种。 通俗的理解为&#xff0c;当以图片的中垂线为x轴和y轴时&#x…

C++从入门到入土(八)——多态的原理

目录 前言 多态的原理 动态绑定与静态绑定 虚函数表 小结 前言 在前面的文章中&#xff0c;我们介绍了C三大特性之一的多态&#xff0c;我们主要介绍了多态的构成条件&#xff0c;但是对于多态的原理我们探讨的是不够深入的&#xff0c;下面这这一篇文章&#xff0c;我们将…

PyCharm安装redis,python安装redis,PyCharm使用失败问题

报错信息 Usage: D:\wb2\wbrj_pys\venv\Scripts\python.exe -m pip install [options] [package-index-options] … D:\wb2\wbrj_pys\venv\Scripts\python.exe -m pip install [options] -r [package-index-options] … D:\wb2\wbrj_pys\venv\Scripts\python.exe -m pip instal…

保姆级离线TiDB V8+解释

以前学习的时候还是3版本&#xff0c;如今已经是8版本了 https://cn.pingcap.com/product-community/?_gl1ujh2l9_gcl_auMTI3MTI3NTM3NC4xNzM5MjU3ODE2_gaMTYwNzE2NTI4OC4xNzMzOTA1MjUz_ga_3JVXJ41175MTc0MTk1NTc1OC4xMS4xLjE3NDE5NTU3NjIuNTYuMC41NDk4MTMxNTM._ga_CPG2VW1Y4…

PyTorch 深度学习实战(17):Asynchronous Advantage Actor-Critic (A3C) 算法与并行训练

在上一篇文章中&#xff0c;我们深入探讨了 Soft Actor-Critic (SAC) 算法及其在平衡探索与利用方面的优势。本文将介绍强化学习领域的重要里程碑——Asynchronous Advantage Actor-Critic (A3C) 算法&#xff0c;并展示如何利用 PyTorch 实现并行化训练来加速学习过程。 一、A…