【数字图像处理】水平翻转、垂直翻转

图像翻转是常见的数字图像处理方式,分为水平翻转和垂直翻转。本文主要介绍 FPGA 实现图像翻转的基本思路,以及使用紫光同创 PGL22G 开发板实现数字图像水平翻转、垂直翻转的过程。

目录

1 水平翻转与垂直翻转

2 FPGA 布署与实现

2.1 功能与指标定义

2.2 逻辑设计

2.3 上板调试


1 水平翻转与垂直翻转

        在数字图像处理中,图像翻转是指将图像进行水平或者垂直方向的翻转,使其呈现不同的效果,分为水平翻转和垂直翻转。

        水平翻转是将图像沿着水平轴线进行翻转,将左半部分和右半部分进行交换。垂直翻转则是将图像沿着垂直轴线进行翻转,将上部分和下部分进行交换。

        使用 FPGA 实现水平翻转时,由于每次向 DDR3 写入一行数据,因此可以借助写 DDR3 之前的 Dual-port RAM,将一行数据进行翻转,实现水平翻转的功能。FPGA 逻辑设计的大致思路是:写 Dual-port RAM 时,写地址从 0 增加;读 Dual-port RAM 写 DDR3 时,读地址从最大值逐步减小到 0 结束。 

        对于垂直翻转功能,则需要借助 DDR3 来实现。像素数据第 1 行写到第 N 行的位置,第 2 行写到第 N-1 行的位置,以此类推。FPGA 逻辑设计的大致思路是:每一行数据写入 DDR3 时,用图像高度减去原来的行地址,作为新的行地址。

2 FPGA 布署与实现

2.1 功能与指标定义

        使用紫光同创 FPGA 平台实现图像翻转功能,FPGA 需要实现的功能与指标如下:

(1)与电脑的串口通信,用于接收上位机下发的图像数据,波特率为 256000 Bd/s;

(2)水平翻转与图像翻转:借助 Dual-port RAM 与 DDR3,分别实现水平翻转与垂直翻转功能;

(3)DDR3 读写控制,将处理前后的图像数据分别写入 DDR3 的不同区域,实现图像的拼接;

(4)HDMI 输出,输出一路 HDMI 信号源,用于将拼接后的图像显示在外接显示器上,分辨率为 1024×768。

2.2 逻辑设计

        图像翻转工程主要的设计模块层次与功能说明如下:

模块名称功能说明
top_uartuart_rx_slice串口接收驱动模块
uart_rx_parse串口数据解析模块,从上位机接收 8bit 原始图像
top_vidinvidin_pipelinepipeline 单元模块,缓存两行图像数据,并将数据提交到 ddr3 数据调度模块
merge_outdvi_timing_genHDMI 视频时序产生模块
dvi_ddr_rd根据 HDMI 控制信号,提交读指令到 ddr3 数据调度模块
dvi_encoderHDMI 输出编码(8b10b 编码)与输出驱动模块

其中,vidin_pipeline 模块实现图像翻转功能,代码如下:

`timescale 1 ns/ 1 ps

`include "../ddr_scheduler/ddr_parameter.vh"

module vidin_pipeline (
   // System level
   sys_rst,
   sys_clk,
   ddr_init_done,
   flip_lr,
   flip_ud,

   // pipeline input ports
   pipeline_in_info,
   pipeline_in_data,
   pipeline_in_wren,
   pipeline_in_end,

   // pipeline output ports
   pipeline_out_info,
   pipeline_out_data,
   pipeline_out_vld,
   pipeline_out_end,

   // User defined ports for ddr_scheduler
   ddr_wr_baseaddr,
   ddr_wr_addr,
   ddr_wr_priority,
   ddr_wr_burstsize,
   ddr_wr_req,
   ddr_wr_ack,
   ddr_wr_end,
   ddr_wr_rden,
   ddr_wr_q,
   ddr_wr_mask
);

// IO direction/register definitions
input                     sys_rst;
input                     sys_clk;
input                     ddr_init_done;
input                     flip_lr;
input                     flip_ud;

input  [31:0]             pipeline_in_info;
input  [31:0]             pipeline_in_data;
input                     pipeline_in_wren;
input                     pipeline_in_end;

output [31:0]             pipeline_out_info;
output [31:0]             pipeline_out_data;
output                    pipeline_out_vld;
output                    pipeline_out_end;

input  [`DDR_A_W-1:0]     ddr_wr_baseaddr;
output [`DDR_A_W-1:0]     ddr_wr_addr;
output                    ddr_wr_priority;
output [`DDR_BURST_W-1:0] ddr_wr_burstsize;
output                    ddr_wr_req;
input                     ddr_wr_ack;
input                     ddr_wr_end;
input                     ddr_wr_rden;
output [`DDR_D_W-1:0]     ddr_wr_q;
output [`DDR_D_W/8-1:0]   ddr_wr_mask;

reg    [31:0]             pipeline_out_info;
reg    [31:0]             pipeline_out_data;
reg                       pipeline_out_vld;
reg                       pipeline_out_end;

// internal signal declarations
reg    [`DDR_CMD_W-1:0]   ddr_cmd_data;
reg                       ddr_cmd_vld;

reg    [9:0]              blk_mem_waddr;
reg    [31:0]             blk_mem_wdata;
reg                       blk_mem_wren;
reg    [9:0]              blk_mem_raddr;
wire   [31:0]             blk_mem_rdata;
reg                       blk_mem_rden;
reg                       blk_mem_rd_busy;
reg                       blk_mem_rd_end;
reg                       blk_mem_rd_vld;

// line_buffer_inst: Dual-port ram for line pixel data buffer
blk_mem_1024x32b line_buffer_inst (
   .wr_data         (blk_mem_wdata   ), // input 32-bit
   .wr_addr         (blk_mem_waddr   ), // input 10-bit
   .wr_en           (blk_mem_wren    ), // input 1-bit
   .wr_clk          (sys_clk         ), // input 1-bit
   .wr_rst          (sys_rst         ), // input 1-bit
   .rd_addr         (blk_mem_raddr   ), // input 10-bit
   .rd_data         (blk_mem_rdata   ), // output 32-bit
   .rd_clk          (sys_clk         ), // input 1-bit
   .rd_rst          (sys_rst         )  // input 1-bit
);
// End of line_buffer_inst instantiation

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst) begin
      blk_mem_waddr <= {10{1'b0}};
      blk_mem_wdata <= {32{1'b0}};
      blk_mem_wren  <= 1'b0;
   end
   else begin
      blk_mem_wdata <= pipeline_in_data;
      blk_mem_wren  <= pipeline_in_wren;

      // Use ping-pong storage here
      if (pipeline_in_end) 
         blk_mem_waddr <= {~blk_mem_waddr[9], {9{1'b0}}};
      else if (pipeline_in_wren) 
         blk_mem_waddr <= {blk_mem_waddr[9], blk_mem_waddr[0+:9]+1'b1};
   end
end

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst) begin
      blk_mem_raddr   <= {10{1'b0}};
      blk_mem_rden    <= 1'b0;
      blk_mem_rd_busy <= 1'b0;
      blk_mem_rd_end  <= 1'b0;
      blk_mem_rd_vld  <= 1'b0;
   end
   else begin
      if (~blk_mem_rd_busy && pipeline_in_end) begin
         blk_mem_rd_busy <= 1'b1;
         if (flip_lr == 1'b0) 
            blk_mem_raddr <= {blk_mem_raddr[9], {9{1'b0}}};
         else
            blk_mem_raddr <= {blk_mem_raddr[9], {9{1'b1}}};
      end
      else if (blk_mem_rd_busy) begin
         // Use ping-pong storage here
         if (flip_lr == 1'b0) begin
            if (& blk_mem_raddr[0+:9]) 
               blk_mem_raddr <= {~blk_mem_raddr[9], {9{1'b0}}};
            else 
               blk_mem_raddr <= {blk_mem_raddr[9], blk_mem_raddr[0+:9]+1'b1};
         end
         else begin
            if (blk_mem_raddr[0+:9] == 0)
               blk_mem_raddr <= {~blk_mem_raddr[9], {9{1'b1}}};
            else
               blk_mem_raddr <= {blk_mem_raddr[9], blk_mem_raddr[0+:9]-1'b1};
         end

         // Pull down read busy flag
         if (flip_lr == 1'b0) begin
            if (& blk_mem_raddr[0+:9]) 
               blk_mem_rd_busy <= 1'b0;
         end
         else begin
            if (blk_mem_raddr[0+:9] == 0)
               blk_mem_rd_busy <= 1'b0;
         end
      end

      blk_mem_rden <= blk_mem_rd_busy;
      blk_mem_rd_vld <= blk_mem_rden;

      if (blk_mem_rd_busy) begin
         if (flip_lr == 1'b0) begin
            if (& blk_mem_raddr[0+:9]) 
               blk_mem_rd_end <= 1'b1;
            else 
               blk_mem_rd_end <= 1'b0;
         end
         else begin
            if (blk_mem_raddr[0+:9] == 0)
               blk_mem_rd_end <= 1'b1;
            else 
               blk_mem_rd_end <= 1'b0;
         end
      end
      else
         blk_mem_rd_end <= 1'b0;
   end
end

always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst) begin
      pipeline_out_info <= {32{1'b0}};
      pipeline_out_data <= {32{1'b0}};
      pipeline_out_vld  <= 1'b0;
      pipeline_out_end  <= 1'b0;
   end
   else begin
      if (pipeline_in_end) 
         pipeline_out_info <= pipeline_in_info;

      pipeline_out_data <= blk_mem_rdata;
      pipeline_out_vld  <= blk_mem_rd_vld;
      pipeline_out_end  <= blk_mem_rd_end;
   end
end

/
always @(posedge sys_rst or posedge sys_clk) begin
   if (sys_rst) begin
      ddr_cmd_data <= {`DDR_CMD_W{1'b0}};
      ddr_cmd_vld <= 1'b0;
   end
   else begin
      if (pipeline_in_end) begin
         ddr_cmd_data[32+:`DDR_BURST_W] <= 8'h7F; // used fixed size here, 512 /4 -1 = 127
         if (flip_ud == 1'b0)
            ddr_cmd_data[0+:28] <= {pipeline_in_info[0+:16], 12'd0};
         else
            ddr_cmd_data[0+:28] <= {16'd383-pipeline_in_info[0+:16], 12'd0};
      end

      if (blk_mem_rd_end) 
         ddr_cmd_vld <= 1'b1;
      else 
         ddr_cmd_vld <= 1'b0;
   end
end

// vid_ddr_wr_inst: ddr write control module
vid_ddr_wr vid_ddr_wr_inst (
   .sys_rst          (sys_rst           ), // input 1-bit
   .sys_clk          (sys_clk           ), // input 1-bit
   .ddr_init_done    (ddr_init_done     ), // input 1-bit
   .vid_cmd_data     (ddr_cmd_data      ), // input 40-bit
   .vid_cmd_vld      (ddr_cmd_vld       ), // input 1-bit
   .vid_img_data     (blk_mem_rdata     ), // input 32-bit
   .vid_img_data_vld (blk_mem_rd_vld    ), // input 1-bit
   .ddr_wr_baseaddr  (ddr_wr_baseaddr   ), // input 27-bit
   .ddr_wr_addr      (ddr_wr_addr       ), // output 27-bit
   .ddr_wr_priority  (ddr_wr_priority   ), // output 1-bit
   .ddr_wr_burstsize (ddr_wr_burstsize  ), // output 8-bit
   .ddr_wr_req       (ddr_wr_req        ), // output 1-bit
   .ddr_wr_ack       (ddr_wr_ack        ), // input 1-bit
   .ddr_wr_end       (ddr_wr_end        ), // input 1-bit
   .ddr_wr_rden      (ddr_wr_rden       ), // input 1-bit
   .ddr_wr_q         (ddr_wr_q          ), // output 128-bit
   .ddr_wr_mask      (ddr_wr_mask       )  // output 16-bit
);
// End of vid_ddr_wr_inst instantiation

endmodule

2.3 上板调试

        使用 PyQt5 和 OpenCV 库编写上位机程序,通过串口发送原始图像数据,以及水平翻转、垂直翻转参数。

# -*- Coding: UTF-8 -*-
import cv2
import sys
import struct
import numpy as np
from PyQt5 import Qt, QtGui, QtCore, QtWidgets, QtSerialPort


class mainWindow(Qt.QWidget):
   def __init__(self, com_port, parent=None):
      super(mainWindow, self).__init__(parent)
      self.setFixedSize(530, 384)
      self.setWindowTitle("PGL OpenCV Tool")

      self.flip_horizontal = False
      self.flip_vertical = False

      # 创建标签与按钮
      self.img_widget = QtWidgets.QLabel()
      self.btn1 = QtWidgets.QPushButton("打开")
      self.btn1.clicked.connect(self.getfile)
      self.btn2 = QtWidgets.QPushButton("关闭")
      self.btn2.clicked.connect(self.close)
      self.btn3 = QtWidgets.QPushButton("水平翻转")
      self.btn3.clicked.connect(self.flip_lr)
      self.btn4 = QtWidgets.QPushButton("垂直翻转")
      self.btn4.clicked.connect(self.flip_ud)

      # 创建布局
      centralLayout = QtWidgets.QVBoxLayout()
      centralLayout.addWidget(self.img_widget)
      bottomLayout = QtWidgets.QHBoxLayout()
      bottomLayout.addWidget(self.btn1)
      bottomLayout.addWidget(self.btn2)
      bottomLayout.addWidget(self.btn3)
      bottomLayout.addWidget(self.btn4)
      centralLayout.addLayout(bottomLayout)
      self.setLayout(centralLayout)

      # 串口对象
      self.COM = QtSerialPort.QSerialPort()
      self.COM.setPortName(com_port)
      self.COM.setBaudRate(256000)
      self.open_status = False
      self.row_cnt = 0
      self.img = None
      self.timer = QtCore.QTimer()
      self.timer.timeout.connect(self.sendImage)
      self.startup()

   def startup(self):
      """Write code here to run once"""
      for com_port in QtSerialPort.QSerialPortInfo.availablePorts():
         print(com_port.portName())

      # Try open serial port
      if not self.COM.open(QtSerialPort.QSerialPort.ReadWrite):
         self.open_status = False
         print("Open Serial Port failed.")
      else:
         self.open_status = True

   def flip_lr(self):
      """水平翻转回调函数"""
      if self.flip_horizontal == False:
         self.flip_horizontal = True
         self.btn3.setStyleSheet("QPushButton{color:rgb(128,128,255)}")
      else:
         self.flip_horizontal = False
         self.btn3.setStyleSheet("QPushButton{color:rgb(0,0,0)}")

   def flip_ud(self):
      """垂直翻转回调函数"""
      if self.flip_vertical == False:
         self.flip_vertical = True
         self.btn4.setStyleSheet("QPushButton{color:rgb(128,128,255)}")
      else:
         self.flip_vertical = False
         self.btn4.setStyleSheet("QPushButton{color:rgb(0,0,0)}")

   def getfile(self):
      """获取图像路径"""
      fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file',
         'C:\\Users\\Administrator\\Pictures', "Image files(*.jpg *.png)")
      self.clipImage(fname[0])
      self.updateImage()
      self.sendImage()

   def clipImage(self, fname):
      """读取并裁剪图片至512x384大小"""
      if fname:
         img = cv2.imread(fname, cv2.IMREAD_COLOR)
         img_roi = img[:384,:512,:]
         print(img_roi.shape)
         cv2.imwrite('./img_roi.png', img_roi)

   def updateImage(self):
      """显示裁剪后的图像"""
      self.img_widget.setPixmap(QtGui.QPixmap('./img_roi.png'))
      self.img = cv2.imread('./img_roi.png')

      if self.open_status:
         self.timer.start(100)

   def sendImage(self):
      """通过串口发送图片"""
      pattern = ">2BH{:d}B".format(512*3)

      # 获取图像翻转信息
      flip_flag = 0x00
      if self.flip_horizontal:
         flip_flag = flip_flag + 0x10
      
      if self.flip_vertical:
         flip_flag = flip_flag + 0x01

      # 发送图像数据
      if self.open_status:
         if self.row_cnt == 384+3:
            self.row_cnt = 0
            self.timer.stop()
         else:
            args1 = [0x55, flip_flag, self.row_cnt]
            args2 = [rgb for rgb in self.img[(self.row_cnt % 384),:].reshape(-1)]
            send_data = struct.pack(pattern, *(args1+args2))
            self.row_cnt += 1
            self.COM.write(send_data)

   def closeEvent(self, event):
      super().closeEvent(event)
      #self.slider_window.close()

      # 定时器停止
      self.timer.stop()
      if self.open_status:
         self.COM.close() # 关闭串口

def main():
   app = QtWidgets.QApplication(sys.argv)
   window = mainWindow('COM21')
   window.show()
   #for win in (window, window.slider_window):
   #   win.show()
   sys.exit(app.exec_())

if __name__ == "__main__":
   main()

        连接 HDMI 线和串口线,选择与发送图像,就可以看到 FPGA 的处理效果了。以下是水平翻转效果。

以下是垂直翻转效果。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【实用工具指南 三】CHAT-GPT4接入指南

好消息&#xff0c;CHAT-GPT4终于开放订阅了&#xff0c;聪明的人已经先用上了&#xff0c;先上个图。 但是去订阅的时候发现银行卡验证不通过&#xff0c;后来一查必须是老美的州才行&#xff0c;于是买了个美元虚拟卡 接下来就比较简单&#xff0c;直接找客服把GPT的充值界…

LabVIEW在高精度机器人视觉定位系统中的应用

在现代工业自动化中&#xff0c;精确的机器人视觉定位系统对于提高生产效率和产品质量至关重要。LabVIEW软件&#xff0c;以其卓越的图像处理和自动化控制功能&#xff0c;在这一领域发挥着重要作用。本案例将展示LabVIEW如何帮助开发和实现一个高精度的机器人视觉定位系统&…

令人绝望的固化和突破-2024-

这是继续写给自己求生之路的记录。 所有成熟稳定的行业都是相对固化的&#xff0c;上升通道及其严苛。 博客 我刚写博客的2015-2017这3年&#xff0c;其实还能带动一些学生&#xff0c;然后部分学生心中有火&#xff0c;眼里有光&#xff0c;也有信心自己做好&#xff0c;还有…

Java里的实用类

1.枚举 语法&#xff1a; public enum 变量名{ 值一&#xff0c;值二} 某个变量的取值范围只能是有限个数的值时&#xff0c;就可以把这个变量定义成枚举类型。 2…装箱&#xff08;boxing&#xff09; 和拆箱&#xff08;unboxing&#xff09; 装箱&#xff08;boxing&…

玩转硬件之玩改朗逸中控设备

这是一个有关一件被拆卸的朗逸中控设备的故事。这个设备已经闲置多年&#xff0c;但是它的命运发生了转变。它被改装成了一台收音机和MP3播放器。 这个设备曾经是一辆朗逸的中控屏幕&#xff0c;就是因为它没有倒车影像&#xff0c;它就被拆了下来&#xff0c;被扔在了一个角落…

系列十三、集合

一、集合 1.1、概述 集合与数组类似&#xff0c;只不过集合中的数据量可以动态的变化。 1.2、体系图 1.3、List集合 1.3.1、特点 存放的数据可以重复且有序。 1.3.2、常见操作 /*** List集合常见操作* */ Test public void listOperateTest() {List<String> cityList …

1.9 day7 IO进程线程

使用消息队列完成两个进程间的通信 进程1 #include <myhead.h> struct migbuf {long a;//消息类型char b[1024];//消息正文 }; #define SIZE (sizeof(struct migbuf)-sizeof(long)) int main(int argc, const char *argv[]) {//创建key值key_t key0;if((keyftok(".…

【算法Hot100系列】下一个排列

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

conda新建、配置python3.8虚拟环境,torch-cuda1.8,torchtext0.9.0,huggingface安装transformers库

起因是我在用bert的时候&#xff0c;导包报错 Python 环境缺少 importlib.metadata 模块。importlib.metadata 是 Python 3.8 引入的模块&#xff0c;而我的环境中使用的 Python 版本为 3.7。所以我得重新配置一个python3.8的环境 准备工作 在开始菜单找到anaconda prompt(an…

mongodb学习篇

目录 前言基本概念数据库-database集合-collection文档-document 部署mongodblinux安装mongodbdocker安装mongodb MongoDB Shell (mongosh)命令行工具mongodb可视化-mongodb-compass、mongo-expressmongodb配置文件mongodb库、集合、文档库基本操作集合基本操作文档的增删改查C…

springBoot-自动配置原理

以下笔记内容&#xff0c; 整理自B站黑马springBoot视频&#xff0c;抖音Holis 1、自动配置原理 1.收集Spring开发者的编程习惯&#xff0c;整理开发过程使用的常用技术列表一>(技术集A) 2.收集常用技术(技术集A)的使用参数&#xff0c;整理开发过程中每个技术的常用设置列表…

关于Js深拷贝的三种方法详细讲解

目录 前言 一、pandas是什么&#xff1f; 二、使用步骤 1.利用函数递归来实现深拷贝 2.利用引入lodash包 3.利用JSON字符串转换 总结 前言 当涉及到JavaScript数据拷贝的时候&#xff0c;深拷贝是一个非常关键的概念。在JavaScript中&#xff0c;对象和数组被认为是引用类型&a…

我在工作一年时怎么都看不懂的编程写法。今天手把手教给你

作为一名程序员&#xff0c;你一定遇到或亲自写过这样的代码。有人将它形象的形容为shi山&#xff0c;或者被戏称为“面向保就业编程”。 以下面这个代码为例&#xff0c;其中的问题也显而易见&#xff0c;当越来越多的条件判断时&#xff0c;代码会变得非常臃肿&#xff0c;难…

Minecraft教程:使用MCSM面板搭建我的世界私服并实现远程联机

文章目录 前言1. 安装JAVA2. MCSManager安装3.局域网访问MCSM4.创建我的世界服务器5.局域网联机测试6.安装cpolar内网穿透7. 配置公网访问地址8.远程联机测试9. 配置固定远程联机端口地址9.1 保留一个固定tcp地址9.2 配置固定公网TCP地址9.3 使用固定公网地址远程联机 前言 Li…

学习笔记之——3D Gaussian Splatting及其在SLAM与自动驾驶上的应用调研

之前博客介绍了NeRF-SLAM&#xff0c;其中对于3D Gaussian Splatting没有太深入介绍。本博文对3D Gaussian Splatting相关的一些工作做调研。 学习笔记之——NeRF SLAM&#xff08;基于神经辐射场的SLAM&#xff09;-CSDN博客文章浏览阅读967次&#xff0c;点赞22次&#xff0…

【野火i.MX6ULL开发板】在MobaXterm平台利用Type-C线串口连接开发板

0、前言 参考文献&#xff1a; http://t.csdnimg.cn/9iRTm http://t.csdnimg.cn/Z0n60 问题&#xff1a;一直识别不出com口&#xff0c; 拟解决思路&#xff1a; 百度网盘重新下载Debian镜像&#xff0c;烧入full版镜像&#xff0c;随便换一下USB插口&#xff08;电脑主机上…

EI级 | Matlab实现VMD-TCN-GRU变分模态分解结合时间卷积门控循环单元多变量光伏功率时间序列预测

EI级 | Matlab实现VMD-TCN-GRU变分模态分解结合时间卷积门控循环单元多变量光伏功率时间序列预测 目录 EI级 | Matlab实现VMD-TCN-GRU变分模态分解结合时间卷积门控循环单元多变量光伏功率时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【EI级】Matlab实现…

图片纹理贴图

/* * 当需要给图形赋予真实颜色的时候&#xff0c;不太可能为没一个顶点指定一个颜色&#xff0c;通常会采用纹理贴图 * 每个顶点关联一个纹理坐标 (Texture Coordinate) 其它片段上进行片段插值 * */#include <iostream> #define STBI_NO_SIMD #define STB_IMAGE_IMPLE…

【Docker】Docker基础

文章目录 安装使用帮助启动命令镜像命令容器命令 安装 # 卸载旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine # 设置存储库 sudo yum install -y yum-utils …

数据结构与算法(十)深度优先搜索与广度优先搜索

广度优先搜索 广度优先搜索&#xff1a;从一个顶点出发&#xff08;由开始时顶点创造顺序优先决定&#xff09;&#xff0c;访问所有没有被访问过的临节点。然后在从被访问过的节点出发&#xff0c;重复之前的操作 如下为一个图 从1出发&#xff0c;先后访问2 3&#xff0c;之后…