Vulkan Tutorial 2 presentation

news2025/1/11 23:38:01

目录

5 窗口表面

6 交换链

7 图像视图


5 窗口表面

由于Vulkan是一个与平台无关的API,它自己不能直接与窗口系统对接。为了在Vulkan和窗口系统之间建立连接,将结果呈现在屏幕上,我们需要使用WSI(窗口系统集成)扩展。

VK_KHR_surface。它暴露了一个 VkSurfaceKHR对象,它代表了一种抽象的表面类型,用于呈现渲染的图像。我们程序中的表面将由我们已经用GLFW打开的窗口来支持。实际上我们已经启用了它,因为它被包含在glfwGetRequiredInstanceExtensions返回的列表中。

在调试回调的下面添加一个surface类成员。

VkSurfaceKHR surface;

VkWin32SurfaceCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
//hwnd和hinstance。这些是窗口和进程的句柄。
createInfo.hwnd = glfwGetWin32Window(window);
//glfwGetWin32Window函数用于从GLFW窗口对象获得原始HWND。
//GetModuleHandle调用返回当前进程的HINSTANCE手柄。
createInfo.hinstance = GetModuleHandle(nullptr);

//创建表面,其中包括实例参数、表面创建细节、自定义分配器和表面句柄要存储的变量。
if (vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
    throw std::runtime_error("failed to create window surface!");
}

GLFW没有提供销毁surface的特殊函数,但这可以很容易地通过原始API完成:确保在实例之前,surface被销毁了。

void cleanup() {
        ...
        vkDestroySurfaceKHR(instance, surface, nullptr);
        vkDestroyInstance(instance, nullptr);
        ...
    }

查询展示支持

尽管Vulkan的实现可能支持窗口系统集成,但这并不意味着系统中的每个设备都支持它。因此我们需要扩展isDeviceSuitable以确保设备可以向我们创建的表面呈现图像。由于呈现是一个队列特定的功能,问题实际上是要找到一个支持向我们创建的表面呈现的队列家族。

struct QueueFamilyIndices {
    std::optional<uint32_t> graphicsFamily;
    std::optional<uint32_t> presentFamily;

    bool isComplete() {
        return graphicsFamily.has_value() && presentFamily.has_value();
    }
};


VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);

//然后简单地检查布尔值,并存储展示家庭队列索引

if (presentSupport) {
    indices.presentFamily = i;
}

//创建展示队列并检索VkQueue句柄。为句柄添加一个成员变量
VkQueue presentQueue;

//要有多个VkDeviceQueueCreateInfo结构来创建两个家族的队列
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);

std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};

float queuePriority = 1.0f;
for (uint32_t queueFamily : uniqueQueueFamilies) {
    VkDeviceQueueCreateInfo queueCreateInfo{};
    queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queueCreateInfo.queueFamilyIndex = queueFamily;
    queueCreateInfo.queueCount = 1;
    queueCreateInfo.pQueuePriorities = &queuePriority;
    queueCreateInfos.push_back(queueCreateInfo);
}

//并修改VkDeviceCreateInfo以指向矢量

createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data();

//如果队列家族是相同的,那么我们只需要传递一次它的索引
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);

6 交换链

Vulkan没有 “默认帧缓冲区”的概念,因此它需要一个基础设施,在我们将缓冲区在屏幕上可视化之前,它将拥有我们要渲染的缓冲区。这个基础设施被称为交换链,必须在Vulkan中明确创建。

交换链本质上是一个等待被呈现到屏幕上的图像队列。我们的应用程序将获取这样的图像来绘制它,然后将其返回到队列中。队列究竟如何工作以及从队列中呈现图像的条件取决于交换链是如何设置的,但是交换链的一般目的是使图像的呈现与屏幕的刷新率同步。

检查交换链的支持情况

由于各种原因,并不是所有的显卡都能够直接将图像呈现在屏幕上,例如因为它们是为服务器设计的,没有任何显示输出。其次,由于图像呈现与窗口系统和与窗口相关的表面有很大的关系,所以它实际上不是Vulkan核心的一部分。你必须在查询到VK_KHR_swapchain设备扩展的支持后启用它。

Vulkan头文件提供了一个很好的宏VK_KHR_SWAPCHAIN_EXTENSION_NAME,它被定义为VK_KHR_swapchain。使用这个宏的好处是,编译器会捕捉到错误的拼写。

const std::vector<const char*> deviceExtensions = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
bool isDeviceSuitable(VkPhysicalDevice device) {
    QueueFamilyIndices indices = findQueueFamilies(device);

    bool extensionsSupported = checkDeviceExtensionSupport(device);

    return indices.isComplete() && extensionsSupported;
}

//修改函数的主体以列举扩展名,并检查所有需要的扩展名是否在其中
 bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
        uint32_t extensionCount;
        vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);

        std::vector<VkExtensionProperties> availableExtensions(extensionCount);
        vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());

        std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());

        for (const auto& extension : availableExtensions) {
            requiredExtensions.erase(extension.extensionName);
        }

        return requiredExtensions.empty();
    }

仅仅检查一个交换链是否可用是不够的,因为它可能实际上与我们的窗口表面不兼容。创建交换链还涉及到比创建实例和设备更多的设置,所以在我们能够继续之前,我们需要查询一些更多的细节。基本上有三种属性是我们需要检查的。

  • 基本表面能力(交换链中图像的最小/最大数量,图像的最小/最大宽度和高度)
  • 表面格式(像素格式、色彩空间)
  • 可用的表现模式

我们将使用一个结构来传递这些细节,一旦它们被查询到。上述三种类型的属性是以下列结构和结构列表的形式出现的:

struct SwapChainSupportDetails {
    VkSurfaceCapabilitiesKHR capabilities;
    std::vector<VkSurfaceFormatKHR> formats;
    std::vector<VkPresentModeKHR> presentModes;
};

现在我们将创建一个新的函数querySwapChainSupport,它将填充这个结构。

SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) 
    {
        SwapChainSupportDetails details;
//表面能力开始。这些属性的查询很简单,并被返回到一个VkSurfaceCapabilitiesKHR结构中
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);

//查询支持的表面格式。因为这是一个结构列表,它遵循熟悉的2个函数调用的仪式
        uint32_t formatCount;
        vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);

        if (formatCount != 0) {
            details.formats.resize(formatCount);
            vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
        }

//查询支持的演示模式
        uint32_t presentModeCount;
        vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);

        if (presentModeCount != 0) {
            details.presentModes.resize(presentModeCount);
            vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
        }

        return details;
    }

如果满足了swapChainAdequate的条件,那么支持肯定是足够的,但是仍然可能有许多不同的模式,有不同的优化。我们现在要写几个函数来找到最佳交换链的正确设置。有三种类型的设置需要确定。

  • 表面格式(颜色深度)
  • 演示模式(将图像 “交换”到屏幕上的条件)
  • 交换范围(交换链中图像的分辨率)

对于这些设置中的每一个,我们都会有一个理想的值,如果有的话,我们就会采用这个值,否则,我们就会建立一些逻辑来寻找下一个最佳值。

VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) 
//每个VkSurfaceFormatKHR'条目包含一个format’和一个colorSpace'成员。
//format成员指定了颜色通道和类型。
    {
        for (const auto& availableFormat : availableFormats) {
            if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {//是否支持SRGB颜色空间
                return availableFormat;
            }
        }

        return availableFormats[0];
    }

//演示模式可以说是交换链最重要的设置,因为它代表了向屏幕显示图像的实际条件
VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
        for (const auto& availablePresentMode : availablePresentModes) {
            if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
                return availablePresentMode;
            }
        }

        return VK_PRESENT_MODE_FIFO_KHR;
    }

//交换范围是交换链图像的分辨率,它几乎总是完全等于我们要绘制的窗口的分辨率*,以像素为单位
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
        if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
            return capabilities.currentExtent;
        }
        else {
            int width, height;
            glfwGetFramebufferSize(window, &width, &height);

            VkExtent2D actualExtent = {
                static_cast<uint32_t>(width),
                static_cast<uint32_t>(height)
            };
//在minImageExtent'和maxImageExtent’的范围内挑选与窗口最匹配的分辨率。
            actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
            actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);

            return actualExtent;
        }
    }

 GLFW在测量尺寸时使用两个单位:像素和屏幕坐标。例如,我们之前在创建窗口时指定的分辨率{WIDTH, HEIGHT}是以屏幕坐标测量的。但是Vulkan是用像素工作的,所以交换链的范围也必须用像素指定。

如果你使用的是高DPI显示器(比如苹果的Retina显示器),屏幕坐标并不对应于像素。相反,由于像素密度较高,窗口的像素分辨率会比屏幕坐标的分辨率大。因此,如果Vulkan不为我们固定交换范围,我们就不能只使用原来的{WIDTH, HEIGHT}。相反,我们必须使用glfwGetFramebufferSize来查询窗口的像素分辨率,然后再与最小和最大图像范围相匹配。

void createSwapChain() {
    SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);

    VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
    VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
    VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);

//除了这些属性之外,我们还必须决定我们希望在交换链中拥有多少图像
//我们建议至少要比最小值多请求一个图像。
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
//不要超过最大的图片数量,其中0是一个特殊的值,意味着没有最大的数量。
        if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) 
        {
            imageCount = swapChainSupport.capabilities.maxImageCount;
        }

//创建交换链对象需要填写一个大的结构
        VkSwapchainCreateInfoKHR createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
        createInfo.surface = surface;

        createInfo.minImageCount = imageCount;
        createInfo.imageFormat = surfaceFormat.format;
        createInfo.imageColorSpace = surfaceFormat.colorSpace;
        createInfo.imageExtent = extent;
        createInfo.imageArrayLayers = 1;
//每个图像所包含的层数。除非你正在开发一个立体的3D应用程序,否则这总是1
        createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
//我们将在交换链中使用图像的哪种操作
}

接下来,我们需要指定如何处理将在多个队列家族中使用的交换链图像。在我们的应用程序中,如果图形队列系列与演示队列不同,就会出现这种情况。我们将从图形队列中绘制交换链中的图像,然后在演示队列中提交它们。有两种方法来处理从多个队列访问的图像。

  • vk_sharing_mode_exclusive。一个图像一次由一个队列家族拥有,在另一个队列家族中使用它之前,必须明确转移所有权。这个选项提供了最好的性能。
  • vk_sharing_mode_concurrent。图像可以在多个队列家族中使用,无需明确的所有权转移。
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
        uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
//队列家族不同使用并发模式
        if (indices.graphicsFamily != indices.presentFamily) {
            createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
            createInfo.queueFamilyIndexCount = 2;
            createInfo.pQueueFamilyIndices = queueFamilyIndices;
        }
        else {
            createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        }

//我们可以指定在交换链中,如果支持某种变换(capabilities中的supportedTransforms
//要指定你不想要任何变换,只需指定当前的变换。
        createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
//是否应该使用alpha通道与窗口系统中的其他窗口进行混合
        createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
        createInfo.presentMode = presentMode;
        createInfo.clipped = VK_TRUE;

        createInfo.oldSwapchain = VK_NULL_HANDLE;

它应该在设备前用vkDestroySwapchainKHR来清理。

检索互换链图像

现在已经创建了交换链,所以剩下的就是检索其中的VkImage的手柄了。在后面的章节中,我们将在渲染操作中引用这些手柄。添加一个类成员来存储句柄。

std::vector<VkImage> swapChainImages;
//这些图像是由交换链的实现创建的,一旦交换链被销毁,它们将被自动清理

//在createSwapChain'函数的末尾添加了检索句柄的代码
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
swapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
//我们只指定了交换链中图像的最低数量,所以实现允许创建一个有更多图像的交换链。
//先用vkGetSwapchainImagesKHR查询最终的图像数量,然后调整容器的大小,最后再调用它来检索手柄。

swapChainImageFormat = surfaceFormat.format;
        swapChainExtent = extent;
//将我们为交换链图像选择的格式和范围存储在成员变量中。

7 图像视图

为了在渲染管道中使用任何VkImage,包括交换链中的对象,我们必须创建一个VkImageView对象。图像视图实际上是对图像的一种观察。它描述了如何访问图像以及访问图像的哪一部分,例如,如果它应该被当作一个没有任何mipmapping层的2D纹理深度纹理。

//编写一个createImageViews函数,为交换链中的每个图像创建一个基本的图像视图
//这样我们就可以在以后将它们作为颜色目标。
std::vector<VkImageView> swapChainImageViews;

//创建createImageViews函数,并在交换链创建后立即调用它。

void createImageViews() {
//调整列表的大小,以适应我们将要创建的所有图像视图。
swapChainImageViews.resize(swapChainImages.size());

//设置循环,在所有交换链图像上进行迭代。
for (size_t i = 0; i < swapChainImages.size(); i++) {
            VkImageViewCreateInfo createInfo{};
//创建图像视图的参数在VkImageViewCreateInfo结构中指定。前面的几个参数是直接的。
            createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
            createInfo.image = swapChainImages[i];
//viewType 和 format字段指定了图像数据的解释方式
            createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
            createInfo.format = swapChainImageFormat;
//components字段允许你对颜色通道进行旋转,我们将坚持使用默认的映射。
            createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
//ubresourceRange字段描述了图像的目的是什么,应该访问图像的哪一部分。
//我们的图像将被用作颜色目标,没有任何mipmapping级别或多个层次。
            createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            createInfo.subresourceRange.baseMipLevel = 0;
            createInfo.subresourceRange.levelCount = 1;
            createInfo.subresourceRange.baseArrayLayer = 0;
            createInfo.subresourceRange.layerCount = 1;

            if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
                throw std::runtime_error("failed to create image views!");
            }
        }

}

与图像不同,图像视图是由我们明确创建的,所以我们需要添加一个类似的循环,在程序结束时再次销毁它们:

void cleanup() {
    for (auto imageView : swapChainImageViews) {
        vkDestroyImageView(device, imageView, nullptr);
    }

    ...
}

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

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

相关文章

【瑞萨RA_FSP】DMAC/DTC——直接存储器访问与数据传输

文章目录 一、DMAC和DTC模块简介1. DMAC 特性2. DTC 特性 二、DMAC 模块框图分析三、DMAC 传输模式1. 正常传输模式2. 重复传输模式3. 块传输模式4. 重复-块传输模式 四、DTC 模块框图分析五、DTC 传输模式1. 正常传输模式2. 重复传输模式3. 块传输模式 六、DMAC和DTC关键特性对…

WMS 概述 -- “窗口管理员“

WMS 概述 -- "窗口管理员" 1、WMS 职责2、涉及元素3、WMS、AMS与Activity间的关系 1、WMS 职责 WMS职责理解窗口管理WMS 是窗口的管理者&#xff0c;它负责窗口的启动、添加和删除&#xff0c;另外窗口的大小和层级也是由WMS 进行管理的。窗口管理的核心成员有 Disp…

结构体总结

目录 1.普通结构体 2.定义结构体并同时建立变量 3.匿名结构体 4.typedef重命名 5.typedef省略结构体名字 6.结构体数组 7.结构体指针 8.结构体嵌套 9.结构体链表&#xff08;头插法&#xff09; 10.结构体中的函数指针 11.结构体的构造函数和初始化列表 1.普通结构体 stru…

chatgpt赋能Python-python_paas

Python PaaS&#xff1a;简介和未来趋势 随着云计算的不断普及&#xff0c;PaaS&#xff08;平台即服务&#xff09;正在成为越来越受欢迎的选择。PaaS可以帮助企业轻松构建、部署和管理应用程序&#xff0c;无需担心底层基础架构的问题。在PaaS领域&#xff0c;Python正在成为…

2023年护网蓝队初级面试总结

00.护网面试步骤是什么样的 投递简历-安全服务公司HR先筛选一下简历&#xff0c;交给技术负责人面试一下&#xff0c;推荐给安全厂商&#xff08;360、奇安信、安恒、绿盟&#xff09; 安全设备厂商HR筛选一下简历&#xff0c;安全设备厂商安排技术笔试和面试&#xff08;技术…

Kubernetes高可用集群二进制部署(Runtime Docker)v1.21版本

Kubernetes高可用集群二进制部署&#xff08;Runtime Docker&#xff09; Kubernetes&#xff08;简称为&#xff1a;k8s&#xff09;是Google在2014年6月开源的一个容器集群管理系统&#xff0c;使用Go语言开发&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xf…

chatgpt赋能Python-python_num怎么用

Python Num怎么用&#xff1f;一个有10年Python编程经验的工程师来告诉你 Python是一种被广泛应用的编程语言&#xff0c;它的发展历程已经超过了20年。而其中的NumPy库则成为了Python编程中最重要的一部分之一。NumPy是一个Python库&#xff0c;它提供了大量针对数字的操作函…

AI宝典:AI超强工具大整合

&#x1f604;&#x1f604;个人介绍 光子郎.进行开发工作七年以上&#xff0c;目前涉及全栈领域并进行开发。会经常跟小伙伴分享前沿技术知识&#xff0c;java后台、web前端、移动端&#xff08;Android&#xff0c;uniapp&#xff0c;小程序&#xff09;相关的知识以及经验体…

微服务实战项目-学成在线-项目介绍以及环境搭建

学成在线-项目介绍&环境搭建 1.项目背景 1.1 在线教育市场环境 以下内容摘自https://report.iresearch.cn/content/2021/01/358854.shtml 在线教育行业是一个有着极强的广度和深度的行业&#xff0c;从校内到校外&#xff1b;从早幼教到职业培训&#xff1b;从教育工具…

Prometheus(普罗米修斯)

Prometheus : 入门 Prometheus简介Prometheus 的主要特点Prometheus架构&#xff1a;什么时候用它合适什么时候用它不合适Prometheus VS InfluxDB基本概念数据模型metric types&#xff08;指标类型&#xff09; Prometheus 安装部署二进制安装部署1、将安装包prometheus-2.6.1…

stable-diffusion-webui(1.2.1版本) win10系统本地电脑部署

在安装stable-diffusion-webui(1.2.1版本)之前需要确认win10本地电脑具有的环境 1.显卡类型&#xff1a;NVIDIA&#xff08;英伟达&#xff09; 建议显存高于4G以上&#xff0c;这样512*512的还是可以运行的 2.python(版本必须最好是3.10.6&#xff09;和 git最新版 正式…

【MySQL高级篇笔记 (上) 】

此笔记为尚硅谷MySQL高级篇部分内容 目录 一、MySQL的数据目录 小结 二 、用户与权限管理 MySQL8密码管理(了解) 权限管理 授予权限的原则 收回权限 权限表 访问控制(了解) 角色管理 三、逻辑架构 服务器处理客户端请求 MySQL 中的 SQL执行流程 SQL语法顺序…

chatgpt赋能Python-python_numpy画图

Python Numpy画图&#xff1a;快速绘制高质量的数据可视化 Python语言不仅在数据科学和人工智能领域得到广泛应用&#xff0c;还被广泛用于数据可视化方面。NumPy是一个Python的科学计算库&#xff0c;提供了高性能的多维数组对象和广播功能&#xff0c;被广泛应用于数据科学、…

Packet Tracer – VLAN 间路由练习

Packet Tracer – VLAN 间路由练习 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 R1 G0/0 172.17.25.2 255.255.255.252 不适用 G0/1.10 172.17.10.1 255.255.255.0 不适用 G0/1.20 172.17.20.1 255.255.255.0 不适用 G0/1.30 172.17.30.1 255.255.255…

十三、人脸识别

文章目录 1、人脸认证和人脸识别2、One shot学习3、siamese network4、Triplet loss function5、人脸识别和二分类问题THE END 1、人脸认证和人脸识别 \qquad 人脸认证表示输入一幅图片和一个name/ID&#xff0c;输出这个图片和ID是否是同一个人。 \qquad 人脸识别表示数据库中…

OMA通道-3

4 Transport API 传输 API 作为开放移动 API 的一部分&#xff0c;为开放移动设备中可用的 SE 提供通信框架 4.1 概述 传输 API 的作用是为应用程序提供访问设备上可用的 SE 的方法。 提供的访问权限基于 ISO/IEC 7816-4 [ISO 7816-4] 定义的概念&#xff1a; • APDU&#…

WIN提权 烂土豆dll劫持

烂土豆配合令牌劫持提权&#xff08;win2012及以下版本可以尝试&#xff09; 两者配合使用可以直接从web权限提升到system权限 msf反弹后监听 上传文件Potato.exe upload /home/yx/桌面/Potato.exe上传至目标主机目录 烂土豆也很鸡肋 在shell中使用 whoami /priv 查看当…

2023年电工杯报名队伍破万!!!!

截止2023年5月24日凌晨0:56分&#xff0c;刚刚使用账号进行电工杯队伍注册&#xff0c;电工杯报名队伍已经达到10600只队伍&#xff0c;作为本年度上半学年&#xff0c;最后一场大型认可度较高的比赛&#xff0c;本次比赛的时间设置、报名费免费等优势使得&#xff0c;这场比赛…

C++ 图像线特征提取及匹配(LineSegmentMatching)

C++ 线特征提取及匹配【LineSegmentMatching】 1 源码下载2 环境配置2.1 添加预定义设置:2.2.配置项目环境2.1 C/C++ --》常规--》附加包含目录:2.2 链接器-》常规--》附加库目录:2.3 链接器-》常规--》输入:3 编译时踩坑记录4.匹配效果输入两幅图像,分别提取两幅图像中的…

【学习日记2023.5.23】 之 Redis入门未入坑

文章目录 1. Redis入门1.1 Redis简介1.2 Redis下载与安装1.2.1 Redis下载1.2.2 Redis安装 1.3 Redis服务启动与停止1.3.1 服务启动命令1.3.2 客户端连接命令1.3.3 修改Redis配置文件1.3.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍2.2 各种数据类型特点 3…