墨水屏显示模拟器程序解读

程序如下:出处https://github.com/tsl0922/EPD-nRF5?tab=readme-ov-file

// GUI emulator for Windows
// This code is a simple Windows GUI application that emulates the display of an e-paper device.
#include <windows.h>
#include <stdint.h>
#include <time.h>
#include "GUI.h"#define BITMAP_WIDTH   400
#define BITMAP_HEIGHT  300
#define WINDOW_WIDTH   400
#define WINDOW_HEIGHT  340
#define WINDOW_TITLE   TEXT("Emurator")// Global variables
HINSTANCE g_hInstance;
HWND g_hwnd;
display_mode_t g_display_mode = MODE_CALENDAR; // Default to calendar mode
BOOL g_bwr_mode = TRUE;  // Default to BWR mode
time_t g_display_time;
struct tm g_tm_time;// Convert bitmap data from e-paper format to Windows DIB format
static uint8_t *convertBitmap(uint8_t *bitmap, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {int bytesPerRow = ((w + 31) / 32) * 4; // Round up to nearest 4 bytesint totalSize = bytesPerRow * h;// Allocate memory for converted bitmapuint8_t *convertedBitmap = (uint8_t*)malloc(totalSize);if (convertedBitmap == NULL) return NULL;memset(convertedBitmap, 0, totalSize);int ePaperBytesPerRow = (w + 7) / 8; // E-paper buffer stridefor (int row = 0; row < h; row++) {for (int col = 0; col < w; col++) {// Calculate byte and bit position in e-paper bufferint bytePos = row * ePaperBytesPerRow + col / 8;int bitPos = 7 - (col % 8); // MSB first (typical e-paper format)// Check if the bit is set in the e-paper bufferint isSet = (bitmap[bytePos] >> bitPos) & 0x01;// Calculate byte and bit position in Windows DIBint dibBytePos = row * bytesPerRow + col / 8;int dibBitPos = 7 - (col % 8); // MSB first for DIB too// Set the bit in the Windows DIB if it's set in the e-paper bufferif (isSet) {convertedBitmap[dibBytePos] |= (1 << dibBitPos);}}}return convertedBitmap;
}// Implementation of the buffer_callback function
void DrawBitmap(uint8_t *black, uint8_t *color, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {HDC hdc;RECT clientRect;int scale = 1;// Get the device context for immediate drawinghdc = GetDC(g_hwnd);if (!hdc) return;// Get client area for positioningGetClientRect(g_hwnd, &clientRect);// Calculate position to center the entire bitmap in the windowint drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2;int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2;// Create DIB for visible pixelsBITMAPINFO bmi;ZeroMemory(&bmi, sizeof(BITMAPINFO));bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmi.bmiHeader.biWidth = w;bmi.bmiHeader.biHeight = -h; // Negative for top-down bitmapbmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 1;bmi.bmiHeader.biCompression = BI_RGB;uint8_t *convertedBitmap = convertBitmap(black, x, y, w, h);if (convertedBitmap == NULL) {ReleaseDC(g_hwnd, hdc);return;}// Set colors for black and white displaybmi.bmiColors[0].rgbBlue = 0;bmi.bmiColors[0].rgbGreen = 0;bmi.bmiColors[0].rgbRed = 0;bmi.bmiColors[0].rgbReserved = 0;bmi.bmiColors[1].rgbBlue = 255;bmi.bmiColors[1].rgbGreen = 255;bmi.bmiColors[1].rgbRed = 255;bmi.bmiColors[1].rgbReserved = 0;// Draw the black layerStretchDIBits(hdc,drawX + x * scale, drawY + y * scale,  // Destination positionw * scale, h * scale,                  // Destination size0, 0,                                 // Source positionw, h,                                 // Source sizeconvertedBitmap,                      // Converted bitmap bits&bmi,                                 // Bitmap infoDIB_RGB_COLORS,                       // UsageSRCCOPY);                             // Raster operation codefree(convertedBitmap);// Handle color layer if present (red in BWR displays)if (color) {// Allocate memory for converted color bitmapuint8_t *convertedColor = convertBitmap(color, x, y, w, h);if (convertedColor) {// Set colors for red overlaybmi.bmiColors[0].rgbBlue = 255;bmi.bmiColors[0].rgbGreen = 255;bmi.bmiColors[0].rgbRed = 0;bmi.bmiColors[0].rgbReserved = 0;bmi.bmiColors[1].rgbBlue = 0;bmi.bmiColors[1].rgbGreen = 0;bmi.bmiColors[1].rgbRed = 0;bmi.bmiColors[1].rgbReserved = 0;// Draw red overlayStretchDIBits(hdc,drawX + x * scale, drawY + y * scale,  // Destination positionw * scale, h * scale,                  // Destination size0, 0,                                 // Source positionw, h,                                 // Source sizeconvertedColor,                       // Converted bitmap bits&bmi,                                 // Bitmap infoDIB_RGB_COLORS,                       // UsageSRCINVERT);                           // Use XOR operation to blendfree(convertedColor);}}// Release the device contextReleaseDC(g_hwnd, hdc);
}// Window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message) {case WM_CREATE:// Initialize the display timeg_display_time = time(NULL) + 8*3600;// Set a timer to update the CLOCK periodically (every second)SetTimer(hwnd, 1, 1000, NULL);return 0;case WM_TIMER:if (g_display_mode == MODE_CLOCK) {g_display_time = time(NULL) + 8*3600;if (g_display_time % 60 == 0) {InvalidateRect(hwnd, NULL, FALSE);}}return 0;case WM_PAINT: {PAINTSTRUCT ps;HDC hdc = BeginPaint(hwnd, &ps);// Get client rect for calculationsRECT clientRect;GetClientRect(hwnd, &clientRect);// Clear the entire client area with a solid colorHBRUSH bgBrush = CreateSolidBrush(RGB(240, 240, 240));FillRect(hdc, &clientRect, bgBrush);DeleteObject(bgBrush);// Use the stored timestampgui_data_t data = {.bwr             = g_bwr_mode,.width           = BITMAP_WIDTH,.height          = BITMAP_HEIGHT,.timestamp       = g_display_time,.temperature     = 25,.voltage         = 3.2f,};// Call DrawGUI to render the interface, passing the BWR modeDrawGUI(&data, DrawBitmap, g_display_mode);EndPaint(hwnd, &ps);return 0;}case WM_KEYDOWN:// Toggle display mode with spacebarif (wParam == VK_SPACE) {if (g_display_mode == MODE_CLOCK)g_display_mode = MODE_CALENDAR;elseg_display_mode = MODE_CLOCK;InvalidateRect(hwnd, NULL, TRUE);}// Toggle BWR mode with R keyelse if (wParam == 'R') {g_bwr_mode = !g_bwr_mode;InvalidateRect(hwnd, NULL, TRUE);}// Handle arrow keys for month/day adjustmentelse if (wParam == VK_UP || wParam == VK_DOWN || wParam == VK_LEFT || wParam == VK_RIGHT) {// Get the current time structureg_tm_time = *localtime(&g_display_time);// Up/Down adjusts monthif (wParam == VK_UP) {g_tm_time.tm_mon++;if (g_tm_time.tm_mon > 11) {g_tm_time.tm_mon = 0;g_tm_time.tm_year++;}}else if (wParam == VK_DOWN) {g_tm_time.tm_mon--;if (g_tm_time.tm_mon < 0) {g_tm_time.tm_mon = 11;g_tm_time.tm_year--;}}// Left/Right adjusts dayelse if (wParam == VK_RIGHT) {g_tm_time.tm_mday++;}else if (wParam == VK_LEFT) {g_tm_time.tm_mday--;}// Convert back to time_tg_display_time = mktime(&g_tm_time);// Force redrawInvalidateRect(hwnd, NULL, TRUE);}return 0;case WM_DESTROY:KillTimer(hwnd, 1);PostQuitMessage(0);return 0;default:return DefWindowProc(hwnd, message, wParam, lParam);}
}// Main entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {g_hInstance = hInstance;// Register window classWNDCLASSA wc = {0}; // Using WNDCLASSA for ANSI versionwc.style = CS_HREDRAW | CS_VREDRAW;wc.lpfnWndProc = WndProc;wc.hInstance = hInstance;wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wc.lpszClassName = "BitmapDemo"; // No L prefix - using ANSI stringsif (!RegisterClassA(&wc)) {MessageBoxA(NULL, "Window Registration Failed!", "Error", MB_ICONEXCLAMATION | MB_OK);return 0;}// Create the window - explicit use of CreateWindowA for ANSI versiong_hwnd = CreateWindowA("BitmapDemo","Emurator", // Using simple titleWS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,WINDOW_WIDTH, WINDOW_HEIGHT,NULL, NULL, hInstance, NULL);if (!g_hwnd) {MessageBoxA(NULL, "Window Creation Failed!", "Error", MB_ICONEXCLAMATION | MB_OK);return 0;}// Show windowShowWindow(g_hwnd, nCmdShow);UpdateWindow(g_hwnd);// Main message loopMSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam;
}

代码功能概述

这段 C 语言代码是一个 Windows GUI 应用程序,用于模拟电子纸显示设备的界面。它支持黑白和黑白红 (BWR) 两种显示模式,并能在时钟和日历两种显示模式间切换。程序通过 Windows API 创建窗口,处理用户输入,并模拟电子纸的显示效果。

主要模块与功能分析


1. 全局变量与宏定义

#define BITMAP_WIDTH   400
#define BITMAP_HEIGHT  300
#define WINDOW_WIDTH   400
#define WINDOW_HEIGHT  340
#define WINDOW_TITLE   TEXT("Emurator")

HINSTANCE g_hInstance;
HWND g_hwnd;
display_mode_t g_display_mode = MODE_CALENDAR;
BOOL g_bwr_mode = TRUE;
time_t g_display_time;
struct tm g_tm_time;


定义了显示区域和窗口的尺寸

声明了窗口句柄、显示模式和时间相关变量

默认显示模式为日历,默认支持 BWR (黑白红) 模式


2. 位图转换函数 convertBitmap

static uint8_t *convertBitmap(uint8_t *bitmap, uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
    // 计算行字节数并分配内存
    int bytesPerRow = ((w + 31) / 32) * 4;
    int totalSize = bytesPerRow * h;
    uint8_t *convertedBitmap = (uint8_t*)malloc(totalSize);
    memset(convertedBitmap, 0, totalSize);
    
    // 转换电子纸格式(MSB优先)到位图格式
    int ePaperBytesPerRow = (w + 7) / 8;
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            // 计算电子纸缓冲区中的位位置
            int bytePos = row * ePaperBytesPerRow + col / 8;
            int bitPos = 7 - (col % 8);
            int isSet = (bitmap[bytePos] >> bitPos) & 0x01;
            
            // 设置Windows DIB中的对应位
            int dibBytePos = row * bytesPerRow + col / 8;
            int dibBitPos = 7 - (col % 8);
            if (isSet) {
                convertedBitmap[dibBytePos] |= (1 << dibBitPos);
            }
        }
    }
    return convertedBitmap;
}

将电子纸设备使用的位图格式转换为 Windows DIB (设备无关位图) 格式

处理了位序转换 (MSB 优先) 和行字节对齐问题

支持黑白和彩色 (红色) 两层显示

DrawBitmap 函数详解

该函数是电子纸模拟器的核心绘制函数,负责将电子纸的位图数据(黑白层和彩色层)转换为 Windows 窗口可显示的位图,并完成最终渲染。

以下从功能流程、关键技术点和代码细节三方面展开分析:

一、函数功能与流程总览

输入参数:

• black:黑白层位图数据(1 位单色,MSB 优先)

• color:彩色层位图数据(可选,通常用于红色显示)

• x/y:绘制起点坐标(相对于显示区域)

• w/h:绘制区域的宽度和高度

 核心流程:

1. 获取绘图环境:获取窗口的设备上下文(HDC)和客户区尺寸。

2. 配置位图信息:定义 Windows 位图格式(BITMAPINFO),包括尺寸、位深、颜色表等。

3. 绘制黑白层: ◦ 调用 convertBitmap 转换电子纸格式为 Windows 位图。 ◦ 使用 StretchDIBits 绘制黑色前景和白色背景。  

4. 绘制彩色层(可选): ◦ 转换彩色层数据并设置颜色表(红色通过黄色与黑色异或实现)。 ◦ 使用 SRCINVERT 光栅操作混合颜色层。  

5. 释放资源:归还设备上下文,避免内存泄漏。  

二、关键技术点解析

1. 设备上下文(HDC)与窗口坐标系

• GetDC(g_hwnd):获取窗口的设备上下文,用于直接在窗口上绘制图形。

• GetClientRect:获取窗口客户区(不含边框和标题栏)的尺寸,

用于计算位图居中显示的位置:

 int drawX = (clientRect.right - BITMAP_WIDTH * scale) / 2;
int drawY = (clientRect.bottom - BITMAP_HEIGHT * scale) / 2;
     
(代码中虽未显式计算 scale,但通过 StretchDIBits 的缩放参数实现自适应显示)

 2. 位图信息头(BITMAPINFO)配置

  BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w;              // 位图宽度(像素)
bmi.bmiHeader.biHeight = -h;            // 负高度表示位图数据从上到下存储(正向显示)
bmi.bmiHeader.biPlanes = 1;             // 平面数,固定为1
bmi.bmiHeader.biBitCount = 1;           // 1位单色位图(每个像素占1位,0=黑色,1=白色)
bmi.bmiHeader.biCompression = BI_RGB;   // 无压缩,使用RGB颜色表
     • 负高度的作用:

Windows 位图有两种存储方式:

◦ 正高度:位图数据从下到上存储(原点在左下角)。

◦ 负高度:位图数据从上到下存储(原点在左上角),更符合常规坐标系,便于直接绘制。  

 3. 位图格式转换(convertBitmap)

• 电子纸格式特点:

◦ 1 位单色,MSB 优先(最高位为第一个像素)。

◦ 行字节数为 (宽度 + 7) / 8(向上取整到字节)。  

• Windows DIB 格式要求: ◦ 1 位位图使用 BI_RGB 压缩,行字节数需为 4 的倍数(通过 ((w + 31) / 32) * 4 计算)。   • 转换逻辑: c        // 电子纸缓冲区中的位位置(MSB优先)
int bitPos = 7 - (col % 8);  
// Windows DIB 中的位位置(同样MSB优先)
int dibBitPos = 7 - (col % 8);  
     
通过逐行逐位复制,将电子纸的 “位掩码” 转换为 Windows 可识别的位图数据。  4. 颜色表与绘制逻辑 • 黑白层绘制: c        bmi.bmiColors[0] = RGB(0, 0, 0); // 索引0对应黑色(位图中值为0的像素)
bmi.bmiColors[1] = RGB(255, 255, 255); // 索引1对应白色(位图中值为1的像素)
StretchDIBits(..., SRCCOPY); // 直接复制像素,黑色前景覆盖白色背景
     
 • 彩色层(红色)绘制:

◦ 电子纸彩色层通常为红色,但 Windows 位图不支持直接绘制红色单通道,因此通过 异或(XOR)操作 模拟:

bmi.bmiColors[0] = RGB(255, 255, 0); // 黄色(R=255, G=255, B=0)
bmi.bmiColors[1] = RGB(0, 0, 0); // 黑色(背景)
StretchDIBits(..., SRCINVERT); // 异或操作:黄色 ^ 白色 = 红色,黄色 ^ 黑色 = 黄色
     
 ◦ 异或原理:

◦ 白色背景区域(RGB (255,255,255)):黄色(RGB (255,255,0))与白色异或后为红色(RGB (255,0,0))。

◦ 黑色前景区域(RGB (0,0,0)):黄色与黑色异或后保持黄色,但因黑色层已覆盖,实际不显示。      三、代码细节与注意事项

1. 内存管理

• 动态分配与释放:

uint8_t *convertedBitmap = convertBitmap(...); // 分配内存
// 使用后立即释放
free(convertedBitmap); 
避免因忘记释放内存导致程序泄漏。  

2. 光栅操作码(Raster Operation)

• SRCCOPY:直接复制源位图到目标区域,覆盖原有像素(用于黑白层)。

• SRCINVERT:源位图与目标区域像素异或(用于彩色层叠加)。

 3. 电子纸特性模拟

• 分层绘制:电子纸通常支持黑白层和彩色层独立更新,此处通过两次 StretchDIBits 调用模拟分层。

• 低刷新率:电子纸实际刷新较慢,但代码中未模拟延迟,仅通过定时器控制界面更新频率。  四、总结 DrawBitmap 函数通过以下步骤实现电子纸显示模拟:

1. 格式适配:将电子纸的位掩码格式转换为 Windows 位图,处理位序和行对齐问题。

2. 分层渲染:先绘制黑白层作为基础,再通过异或操作叠加彩色层(红色)。

3. 资源管理:及时释放内存和设备上下文,确保程序稳定性。  该函数是电子纸模拟器的核心渲染引擎,结合窗口消息处理和用户输入,最终实现了可交互的电子纸界面效果。


  

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

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

相关文章

【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer

【技海登峰】Kafka漫谈系列(十一)SpringBoot整合Kafka之消费者Consumer spring-kafka官方文档: https://docs.spring.io/spring-kafka/docs/2.8.10/reference/pdf/spring-kafka-reference.pdf KafkaTemplate API: https://docs.spring.io/spring-kafka/api/org/springframe…

【言语理解】逻辑填空之逻辑对应11

front&#xff1a;词义辨析 11.1前后解释对应 填空的词汇大意可能是吖要结合实际情况不要一味高估导致适得其反的结果 未雨绸缪&#xff1a;趁着天没下雨&#xff0c;先修缮房屋门窗。比喻事先做好准备工作&#xff0c;预防意外的事发生。&#xff08;提前做好准备&#xff0c…

ubuntu上 opencv + eclipse + C++

ubuntu上 opencv eclipse C 1. 安装eclipse 安装eclipse不用说了&#xff0c;前置条件要安装java 配置快捷键方式 2. 新建c项目 配置opencv环境 project -> properties: 配置c标准库版本&#xff1a; 配置opencv头文件&#xff1a; 配置opencv库文件&#xff1a;…

动态内存管理2+柔性数组

一、动态内存经典笔试题分析 分析错误并改正 题目1 void GetMemory(char *p) {p (char *)malloc(100); } void Test(void) {char *str NULL;GetMemory(str);strcpy(str, "hello world");printf(str); } int main() {Test();return 0; }错误的原因&#xff1a; …

AI写PPT可以用吗?我测试了3款AI写PPT工具,分享感受

上周五临下班&#xff0c;领导突然让我周末赶出一份季度营销报告 PPT&#xff0c;还要求周一晨会展示。看着空荡荡的 PPT 页面&#xff0c;我满心都是绝望 —— 周末不仅泡汤&#xff0c;搞不好还得熬夜到凌晨。好在同部门的前辈给我推荐了几款 AI 写 PPT 工具&#xff0c;没想…

PrimeVul论文解读-如何构建高质量漏洞标签与数据集

目录 1. 引入2. 现有漏洞识别方案的不足2.1 数据集中label不准2.2 数据重复2.3 测评标准不够好 3. 现有漏洞识别数据集分析3.1 关于现有数据集中label的准确率分析3.2 关于现有数据集中数据泄露&#xff08; Data Leakage&#xff09;情况分析 4. 漏洞识别测评5. PrimeVul数据集…

关于数据湖和数据仓的一些概念

一、前言 随着各行业数字化发展的深化,数据资产和数据价值已越来越被深入企业重要发展的战略重心,海量数据已成为多数企业生产实际面临的重要问题,无论存储容量还是成本,可靠性都成为考验企业数据治理的考验。本文来看下海量数据存储的数据湖和数据仓,数据仓库和数据湖,…

linux-----------------库制作与原理(下)

1.ELF文件 要理解编译链链接的细节&#xff0c;我们不得不了解⼀下ELF⽂件。其实有以下四种⽂件其实都是ELF⽂件&#xff1a; • 可重定位⽂件&#xff08;Relocatable File &#xff09; &#xff1a;即 xxx.o ⽂件。包含适合于与其他⽬标⽂件链接来创 建可执⾏⽂件或者共享…

python-爬虫基础

爬虫本质&#xff1a;通过编写程序来获取到互联网上的资源。 我们的程序本质上就是模拟浏览器 一个简单的小爬虫&#xff1a; 只需要三步&#xff1a; from urllib.request import urlopen #url是网址&#xff0c;request意思是请求 这里跑出来的中文是这样的注意看&#…

单元化架构

目录 ​​​​​​​​编辑 单元化 逻辑单元 单元化 多地多机房部署&#xff0c;是互联网系统的必然发展方向&#xff0c;一个系统要走到这一步&#xff0c;也就必然要解决上面提到的问题&#xff1a;流量调配、数据拆分、延时等。业界有很多技术方案可以用来解决这些问题&…

【免杀】C2免杀技术(五)动态API

一、什么是动态API 在C2免杀领域中&#xff0c;“动态API” 主要指的是绕过静态检测的一种技术手段&#xff0c;其本质是运行时动态解析和调用Windows API函数&#xff0c;而不是在程序编译阶段就明确引用这些API。这种方式可以有效躲避静态分析工具和杀软的签名识别。 为什么…

Python爬虫实战:研究JavaScript压缩方法实现逆向解密

一、引言 在数字化信息爆炸的时代,网络数据已成为驱动各行业发展的核心资产。Python 凭借其丰富的库生态和简洁的语法,成为网络爬虫开发的首选语言。然而,随着互联网安全防护机制的不断升级,网站普遍采用 JavaScript 压缩与混淆技术保护其核心逻辑和数据传输,这使得传统爬…

HTTP 请求走私(HTTP Request Smuggling)

HTTP 请求走私&#xff08;HTTP Request Smuggling&#xff09;是一种通过利用前端代理&#xff08;如负载均衡器、CDN&#xff09;和后端服务器在 解析 HTTP 请求时存在不一致性 的漏洞&#xff0c;从而实现 注入恶意请求 的攻击技术。 一、基本原理 HTTP 请求走私主要依赖两…

【Google机器学习实践指南(线性回归篇)

&#x1f50d; Google机器学习实践指南&#xff08;线性回归篇&#xff09; Google机器学习实战(3)-单变量线性回归核心解析&#xff0c;掌握房价预测模型 一、建模流程全景图 ▲ 四大核心步骤&#xff1a; 数据可视化→特征工程→模型训练→预测推理 二、房价预测实战 1. …

python打卡day16

NumPy 数组基础 因为前天说了shap&#xff0c;这里涉及到数据形状尺寸问题&#xff0c;所以需要在这一节说清楚&#xff0c;后续的神经网络我们将要和他天天打交道。 知识点&#xff1a; numpy数组的创建&#xff1a;简单创建、随机创建、遍历、运算numpy数组的索引&#xff1a…

ubuntu 20.04 更改国内镜像源-阿里源 确保可用

镜像源是跟linux版本一一对应的,查询自己系统的版本号&#xff1a; 命令&#xff1a;lsb_release -a macw:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal macw:~$…

基于OpenCV的SIFT特征和FLANN匹配器的指纹认证

文章目录 引言一、概述二、代码解析1. 图像显示函数2. 核心认证函数2.1 创建SIFT特征提取器2.2 检测关键点和计算描述符&#xff08;源图像&#xff09;2.3 检测关键点和计算描述符&#xff08;模板图像&#xff09;2.4 创建FLANN匹配器2.5 使用K近邻匹配 3. 匹配点筛选4. 认证…

四品种交易策略

策略概述 策略思路: 交易品种:同时交易四个品种,每个品种使用总资金的10%。 合约选择:使用连续合约(data0)发出交易信号,实际交易 主力合约(data1)和下一个主力合约(data2)。 资金管理:总资金用A_CurrentEquity表示,交易手数据此计算。 止损执行:盘中达到止损…

MySQL事务的一些奇奇怪怪知识

Gorm事务有error却不返回会发生什么 Gorm包是大家比较高频使用。正常的用法是&#xff0c;如果有失败返回error&#xff0c;整体rollback&#xff0c;如果不返回error则commit。下面是Transaction的源码&#xff1a; // Transaction start a transaction as a block, return …

时序数据库、实时数据库与实时数仓:如何为实时数据场景选择最佳解决方案?

随着物联网、金融交易、在线游戏等场景对实时数据处理需求的增长&#xff0c;市场上涌现出多种专门针对实时数据处理的数据库解决方案。然而&#xff0c;面对时序数据库、实时数据库和实时数据仓库这三种看似相似的技术&#xff0c;许多技术决策者常常感到困惑&#xff1a;它们…