Qt 基于海康相机的视频绘图

news2024/11/21 2:36:33

需求

在视频窗口上进行绘图,包括圆,矩形,扇形等

效果

 思路:

自己取图然后转成QImage ,再向QWidget 进行渲染,根据以往的经验,无法达到很高的帧率。因此决定使用相机SDK自带的渲染功能,也就是传一个句柄给到sdk。但是这样视频渲染出来了,向上绘制图案,会被视频遮挡住,因此这里采用了两个窗口叠加,然后上层窗口设置透明背景的方式来实现。

底层取图窗口代码:

#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H

#include <QWidget>
#include <windows.h>
#include <MvCameraControl.h>

#include "./util/PSEventController.h"
#include "graphwidget.h"
class CameraWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CameraWidget(QWidget *parent = nullptr);
    ~CameraWidget();

    void updatePos(int x,int y);

private:
    bool findDevice();
    bool printDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo);
    void getImage();
    bool openDevice();
    bool closeDevice();

private:
    int nRet = MV_OK;
    void* handle = NULL;
    MV_CC_DEVICE_INFO_LIST stDeviceList = {0};
    std::atomic_bool bExit = true;
    HWND hwnd = NULL;

    GraphWidget * graphWidget=nullptr;
    QWidget *videoWidget =nullptr;

    std::atomic_bool isCapture{false};

private:
    void initData();
    void mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo);

public slots:
    void on_psEvent_capture(bool isChecked);
    void on_psEvent_adjustImage(bool isChecked);
    void on_psEvent_fixImage(bool isChecked);

signals:
    void capture(QImage image);
};

#endif // CAMERAWIDGET_H


#include "camerawidget.h"

#include <iostream>
#include <mutex>
#include <thread>
#include <QWidget>
#include <QPainter>
#include <QGridLayout>
#include <QStackedLayout>
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>

CameraWidget::CameraWidget(QWidget *parent)
    : QWidget{parent}
{
    graphWidget = new GraphWidget(this);
    graphWidget->setWindowFlags(Qt::FramelessWindowHint|Qt::Dialog|Qt::WindowStaysOnTopHint|Qt::SubWindow);
    graphWidget->setAttribute(Qt::WA_TranslucentBackground, true);
    QPalette pal;
    pal.setColor(QPalette::Window,QColor(0,0,0,0));
    graphWidget->setAutoFillBackground(true);
    graphWidget->setPalette(pal);
    graphWidget->show();

    hwnd = (HWND)this->winId();
    openDevice();

    this->setFixedSize(816,683);
    graphWidget->setFixedSize(this->size());

    setUpdatesEnabled(false);
    setAttribute(Qt::WA_OpaquePaintEvent);

    initData();
}

CameraWidget::~CameraWidget()
{
    closeDevice();
}


bool CameraWidget::findDevice()
{
    //枚举设备
    nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
    if (MV_OK != nRet)
    {
        printf("Enum Devices fail! nRet [0x%x]\n", nRet);
        return false;
    }

    if (stDeviceList.nDeviceNum > 0)
    {
        for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
        {
            printf("[device %d]:\n", i);
            MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
            if (NULL == pDeviceInfo)
            {
                break;
            }
            printDeviceInfo(pDeviceInfo);
        }
    }
    else
    {
        printf("Find No Devices!\n");
        return false;
    }
    return true;
}

bool CameraWidget::openDevice()
{
    if(!findDevice()){
        return false;
    }

    unsigned int nIndex = 0;
    if (nIndex >= stDeviceList.nDeviceNum)
    {
        printf("Invalid device index!\n");
        return false;
    }

    do
    {
        //选择设备并创建句柄
        nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
        if (MV_OK != nRet)
        {
            printf("Create Handle fail! nRet [0x%x]\n", nRet);
            break;
        }

        // ch:打开设备
        nRet = MV_CC_OpenDevice(handle);
        if (MV_OK != nRet)
        {
            printf("Open Device fail! nRet [0x%x]\n", nRet);
            break;
        }

        // ch:探测网络最佳包大小(只对GigE相机有效)
        if (stDeviceList.pDeviceInfo[nIndex]->nTLayerType == MV_GIGE_DEVICE)
        {
            int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
            if (nPacketSize > 0)
            {
                nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
                if(nRet != MV_OK)
                {
                    printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
                }
            }
            else
            {
                printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
            }
        }

        //设置触发模式为off
        nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
        if (MV_OK != nRet)
        {
            printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
            break;
        }

        // ch:开始取流 | en:Start grab image
        nRet = MV_CC_StartGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
            break;
        }
        bExit=false;

        std::thread t([&](){
            getImage();
        });
        t.detach();

        return true;
    }while (0);


    if (nRet != MV_OK)
    {
        if (handle != NULL)
        {
            MV_CC_DestroyHandle(handle);
            handle = NULL;
        }
    }

    return false;
}

bool CameraWidget::closeDevice()
{
    bExit=true;

    if (handle == NULL)
        return true;

    do{
        // ch:停止取流 | en:Stop grab image
        nRet = MV_CC_StopGrabbing(handle);
        if (MV_OK != nRet)
        {
            printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
            break;
        }

        // ch:关闭设备 | Close device
        nRet = MV_CC_CloseDevice(handle);
        if (MV_OK != nRet)
        {
            printf("ClosDevice fail! nRet [0x%x]\n", nRet);
            break;
        }

        // ch:销毁句柄 | Destroy handle
        nRet = MV_CC_DestroyHandle(handle);
        if (MV_OK != nRet)
        {
            printf("Destroy Handle fail! nRet [0x%x]\n", nRet);
            break;
        }

        handle = NULL;
        return true;
    }while (0);

    if (nRet != MV_OK)
    {
        if (handle != NULL)
        {
            MV_CC_DestroyHandle(handle);
            handle = NULL;
        }
    }

    return false;
}

void CameraWidget::initData()
{
    PSEventController::subscribe(this,"capture");
    PSEventController::subscribe(this,"adjustImage");
    PSEventController::subscribe(this,"fixImage");

    connect(this,&CameraWidget::capture,this,[&](QImage image){
       graphWidget->setBackgroundImage(QPixmap::fromImage(image),true);
    },Qt::UniqueConnection);
}

void CameraWidget::on_psEvent_capture(bool isChecked)
{
    if(!isChecked){
        QPixmap backgroundImage;
        graphWidget->setBackgroundImage(backgroundImage,false);
    }else{
        isCapture=true;
    }
}

void CameraWidget::on_psEvent_adjustImage(bool isChecked)
{
    graphWidget->setIsScale(true);
}

void CameraWidget::on_psEvent_fixImage(bool isChecked)
{
    graphWidget->setIsScale(false);
}

void CameraWidget::updatePos(int x, int y)
{
    graphWidget->move(x,y);
}

bool CameraWidget::printDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo)
{
    if (NULL == pstMVDevInfo)
    {
        printf("The Pointer of pstMVDevInfo is NULL!\n");
        return false;
    }
    if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
    {
        int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
        int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
        int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
        int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

        // ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined name
        printf("CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
        printf("UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
    }
    else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
    {
        printf("UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
        printf("Serial Number: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
        printf("Device Number: %d\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.nDeviceNumber);
    }
    else
    {
        printf("Not support.\n");
    }

    return true;
}

//std::once_flag flag;
void CameraWidget::getImage()
{
    int nRet = MV_OK;
    MV_FRAME_OUT stImageInfo = {0};
    MV_DISPLAY_FRAME_INFO stDisplayInfo = {0};

    while(1)
    {
        nRet = MV_CC_GetImageBuffer(handle, &stImageInfo, 1000);
        if (nRet == MV_OK)
        {
            // printf("Get Image Buffer: Width[%d], Height[%d], FrameNum[%d]\n",
            //  stImageInfo.stFrameInfo.nWidth, stImageInfo.stFrameInfo.nHeight, stImageInfo.stFrameInfo.nFrameNum);

            if (hwnd)
            {
                stDisplayInfo.hWnd = hwnd;
                stDisplayInfo.pData = stImageInfo.pBufAddr;
                stDisplayInfo.nDataLen = stImageInfo.stFrameInfo.nFrameLen;
                stDisplayInfo.nWidth = stImageInfo.stFrameInfo.nWidth;
                stDisplayInfo.nHeight = stImageInfo.stFrameInfo.nHeight;
                stDisplayInfo.enPixelType = stImageInfo.stFrameInfo.enPixelType;

                //转qt QImage 给到绘图窗口
                if(isCapture){
                    mvToQImage(stDisplayInfo);
                }


                //调整窗口尺寸
                //                std::call_once(flag, [&](){
                //                    int cW = stImageInfo.stFrameInfo.nWidth;
                //                    int cH = stImageInfo.stFrameInfo.nHeight;
                //                });

                MV_CC_DisplayOneFrame(handle, &stDisplayInfo);
            }

            nRet = MV_CC_FreeImageBuffer(handle, &stImageInfo);
            if(nRet != MV_OK)
            {
                printf("Free Image Buffer fail! nRet [0x%x]\n", nRet);
            }
        }
        else
        {
            printf("Get Image fail! nRet [0x%x]\n", nRet);
        }
        if(bExit)
        {
            break;
        }
    }
}

void CameraWidget::mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo)
{
    QImage image;
    if(stDisplayInfo.enPixelType==PixelType_Gvsp_Mono8){
        image= QImage(stDisplayInfo.pData, stDisplayInfo.nWidth, stDisplayInfo.nHeight, QImage::Format_Indexed8);
    }else if(stDisplayInfo.enPixelType==PixelType_Gvsp_RGB8_Packed){
        image= QImage(stDisplayInfo.pData, stDisplayInfo.nWidth, stDisplayInfo.nHeight, QImage::Format_RGB888);
    }
    emit capture(image);
    isCapture=false;
}

上层绘图窗口代码:

#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H

#include <QWidget>
#include <windows.h>
#include <MvCameraControl.h>

#include "./util/PSEventController.h"
#include "graphwidget.h"
class CameraWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CameraWidget(QWidget *parent = nullptr);
    ~CameraWidget();

    void updatePos(int x,int y);

private:
    bool findDevice();
    bool printDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo);
    void getImage();
    bool openDevice();
    bool closeDevice();

private:
    int nRet = MV_OK;
    void* handle = NULL;
    MV_CC_DEVICE_INFO_LIST stDeviceList = {0};
    std::atomic_bool bExit = true;
    HWND hwnd = NULL;

    GraphWidget * graphWidget=nullptr;
    QWidget *videoWidget =nullptr;

    std::atomic_bool isCapture{false};

private:
    void initData();
    void mvToQImage(MV_DISPLAY_FRAME_INFO &stDisplayInfo);

public slots:
    void on_psEvent_capture(bool isChecked);
    void on_psEvent_adjustImage(bool isChecked);
    void on_psEvent_fixImage(bool isChecked);

signals:
    void capture(QImage image);
};

#endif // CAMERAWIDGET_H

#include "graphwidget.h"
#include <QGridLayout>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>

#include "../graphics/bqgraphicsitem.h"

#define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH  viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height()

GraphWidget::GraphWidget(QWidget *parent)
    : QGraphicsView{parent}
{
    setAttribute(Qt::WA_TranslucentBackground);
    setStyleSheet("background: transparent;border:0px");
    setWindowFlags(Qt::FramelessWindowHint);
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setRenderHint(QPainter::Antialiasing);
    scene = new QGraphicsScene(this);
    this->setScene(scene);
    setDragMode(ScrollHandDrag);
    this->setSceneRect(this->geometry());
    centerOn(0, 0);

    initData();
}

void GraphWidget::setIsScale(bool newIsScale)
{
    isScale = newIsScale;
    if(!isScale){
        revertSize();
    }
}

void GraphWidget::setBackgroundImage(const QPixmap &newBackgroundImage,bool newIsSetBackground)
{
    qDebug()<<"setBackgroundImage "<<newIsSetBackground;
    isSetBackground=newIsSetBackground;
    if(backgroundItem){
        scene->removeItem(backgroundItem);
        backgroundItem=nullptr;
    }

    if(isSetBackground){
        setAttribute(Qt::WA_TranslucentBackground,false);
        backgroundImage = newBackgroundImage;
        if(!backgroundImage.isNull()){
            backgroundItem = scene->addPixmap(backgroundImage);
            backgroundItem->setPos(-this->width()/2,-this->height()/2);
            backgroundItem->setZValue(-1000);

            backgroundItem->setFlags(QGraphicsItem::ItemIsSelectable |
                               QGraphicsItem::ItemIsMovable |
                               QGraphicsItem::ItemIsFocusable);
            update();
        }
    }else{
        setAttribute(Qt::WA_TranslucentBackground,true);
        revertSize();
    }

}

void GraphWidget::clearItem()
{
    for(int i=0;i<scene->items().size();i++){
        QGraphicsItem *item = scene->items().at(i);
        if(item->zValue()==-1000){
            continue;
        }else{
            scene->removeItem(scene->items().at(i));
        }
    }
}

void GraphWidget::on_psEvent_addLine(bool isChecked)
{
    clearItem();
    BRectangle *m_rectangle = new BRectangle(0, 0, 100, 50, BGraphicsItem::ItemType::Rectangle);
    scene->addItem(m_rectangle);
}

void GraphWidget::on_psEvent_addCircle(bool isChecked)
{
    clearItem();
    BConcentricCircle *m_conCircle = new BConcentricCircle(0, 0, 50, 80, BGraphicsItem::ItemType::Concentric_Circle);
    scene->addItem(m_conCircle);
}

void GraphWidget::on_psEvent_addEllipse(bool isChecked)
{
    clearItem();
    BEllipse *m_ellipse = new BEllipse(0, 0, 100, 50, BGraphicsItem::ItemType::Ellipse);
    scene->addItem(m_ellipse);
}

void GraphWidget::on_psEvent_addArc(bool isChecked)
{
    clearItem();
    BPie *m_pie = new BPie(0, 0, 80, 30, BGraphicsItem::ItemType::Pie);
    scene->addItem(m_pie);
}

void GraphWidget::wheelEvent(QWheelEvent *event)
{
    if(isScale){
        static float scale = 1.1;
        auto angle = event->angleDelta();

        if(angle.y() > 0)
        {
            this->scale(scale, scale);
        }
        else
        {
            this->scale(1/scale, 1/scale);
        }
    }
}

void GraphWidget::initData()
{
    PSEventController::subscribe(this,"addLine");
    PSEventController::subscribe(this,"addCircle");
    PSEventController::subscribe(this,"addEllipse");
    PSEventController::subscribe(this,"addArc");
}

void GraphWidget::revertSize()
{
    setTransformationAnchor(QGraphicsView::AnchorViewCenter);
    QMatrix q;
    q.setMatrix(1,this->matrix().m12(),this->matrix().m21(),1,this->matrix().dx(),this->matrix().dy());
    setMatrix(q,false);
}

主窗口移动和缩放时更新视频窗口位置:

void MainWindow::updateGraphWidgetPos()
{
    if(cameraWidget){
        QPoint p =  mapToGlobal(cameraWidget->parentWidget()->pos());
        cameraWidget->updatePos(p.x(),p.y()+22);
    }
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    updateGraphWidgetPos();
    return QWidget::resizeEvent(e);
}

void MainWindow::moveEvent(QMoveEvent *e)
{
    updateGraphWidgetPos();
    return QWidget::moveEvent(e);
}

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

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

相关文章

利用 React 和 Bootstrap 进行强大的前端开发

文章目录 介绍React 和 Bootstrap设置环境使用 Bootstrap 创建 React 组件React-Bootstrap 组件结论 介绍 创建响应式、交互式和外观引人入胜的 Web 界面是现代前端开发人员的基本技能。幸运的是&#xff0c;借助 React 和 Bootstrap 等工具的出现&#xff0c;制作这些 UI 变得…

目标分割技术-语义分割总览

前言 博主现任高级人工智能工程师&#xff0c;曾发表多篇SCI且获得过多次国际竞赛奖项&#xff0c;理解各类模型原理以及每种模型的建模流程和各类题目分析方法。目的就是为了让零基础快速使用各类代码模型&#xff0c;每一篇文章都包含实战项目以及可运行代码。欢迎大家订阅一…

Simulia 2022 新功能

增材制造 达索系统增材制造解决方案实现了端到端一体化全流程解决方案&#xff0c;可以实现从原材料研究到创成式设计、工艺设计、工艺仿真仿真、并且还延续到增材制造完成后的热处理、线切割等工艺&#xff0c;涵盖了各个方面的内容。 达索系统针对增材制造各个环节在每一个…

python数据结构与算法-06_算法分析

算法复杂度分析 前面我们说了很多次时间复杂度是 O(1), O(n) 啥的&#xff0c;并没有仔细讲解这个 O 符号究竟是什么。 你可以大概理解为操作的次数和数据个数的比例关系。比如 O(1) 就是有限次数操作&#xff0c;O(n) 就是操作正比于你的元素个数。 这一章我们用更严谨的方式…

以makefile的方式在linux上编译代码(小白级别)

作者&#xff1a;爱塔居 作者简介&#xff1a;大四学生&#xff0c;分享自己的学习片段~ 目录 前言 一、创建主要文件 二、makefile 前言 多有不足&#xff0c;以供参考&#xff0c;欢迎大佬们指点。我是在虚拟机上执行的&#xff0c;应该都一样。我用的VirtualBox&#xff0c;…

PHP/Lerv通过经纬度计算距离获取附近商家

实际开发中,常常需要获取用户附近的商家,思路是 获取用户位置(经纬度信息)在数据库中查询在距离范围内的商家 注: 本文章内计算距离所使用地球半径统一为 6378.138 km public function mpa_list($latitude,$longitude,$distance){// $latitude 34.306465;// $longitude 10…

Redis篇---第十一篇

系列文章目录 文章目录 系列文章目录前言一、说说Redis持久化机制二、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题三、热点数据和冷数据是什么前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章…

Android WMS——输入系统管理(十七)

一、简介 1、工作原理 输入子系统从驱动文件中读取事件后,再封装提交给 IMS,IMS 再发送给 WMS 进行处理。 Android 输入系统的工作原理概括来说,内核将原始事件写入到设备节点中,InputReader 不断地通过 EventHub 将原始事件取出来并翻译加工成 Android 输入事件,…

抖音电商双11官方数据最全汇总!

11月13日&#xff0c;抖音电商数据发布“抖音商城双11好物节”数据报告&#xff0c;展现双11期间平台全域经营情况及大众消费趋势。 报告显示&#xff0c;10月20日至11月11日&#xff0c;抖音电商里的直播间累计直播时长达到5827万小时&#xff0c;挂购物车的短视频播放了1697亿…

引入 requests.codes 模块

在网络应用开发中&#xff0c;处理HTTP请求状态码是一项常见的任务。然而&#xff0c;使用Python的requests库时&#xff0c;我们会发现一个不便之处&#xff1a;requests库没有提供一个方便的方式来管理和引用HTTP请求状态码。 在使用requests库进行HTTP请求时&#xff0c;我…

jenkins传参给robotframework

在做自动化的时候&#xff0c;需要使用jenkins传参给rf&#xff0c;rf根据传来的变量运行&#xff0c;在将变量传递给py脚本文件。特此记录。 一、配置jenkins 构建的命令使用如下格式即可&#xff08;注意空格&#xff09;&#xff1a; cd D:\xxx\test call pybot --variabl…

【数据结构】【版本2.0】【树形深渊】——二叉树入侵

目录 引言 一、树的概念与结构 1.1 树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用 二、二叉树的概念与结构 2.1 二叉树的概念 2.2 特殊二叉树 满二叉树 完全二叉树 2.3 现实中的二叉树 2.4 二叉树的性质 2.5 二叉树的存储结构 顺序存储 链式…

这篇文章带你了解:如何一次性将Centos中Mysql的数据快速导出!!!

目录 一.数据库导出 1.首先创建文件以.sql结尾的文件 2.打开名mysq的解压目录&#xff0c;导出数据 3.然后在查看即可 4 需要的软件 MobaXterm 一.数据库导出 1.首先创建文件以.sql结尾的文件 通过 touch ssm.sql &#xff08;小编&#xff09; 实际上&#xff1a…

提升办公效率,畅享多功能办公笔记软件Notion for Mac

在现代办公环境中&#xff0c;高效的笔记软件对于提高工作效率至关重要。而Notion for Mac作为一款全能的办公笔记软件&#xff0c;将成为你事业成功的得力助手。 Notion for Mac以其多功能和灵活性而脱颖而出。无论你是需要记录会议笔记、管理项目任务、制定流程指南&#xf…

光谱图像超分辨率综述

光谱图像超分辨率综述 简介 ​ 论文链接&#xff1a;A Review of Hyperspectral Image Super-Resolution Based on Deep Learning UpSample网络框架 1.Front-end Upsampling ​ 在Front-end上采样中&#xff0c;是首先扩大LR图像&#xff0c;然后通过卷积网络对放大图像进行…

Linux安装rabbitMq(亲测可用)解决只能本地访问的问题

安装er https://blog.csdn.net/laterstage/article/details/131513793?spm1001.2014.3001.5501下载mq wget --content-disposition "https://packagecloud.io/rabbitmq/rabbitmq-server/packages/el/7/rabbitmq-server-3.10.0-1.el7.noarch.rpm/download.rpm?distro_v…

阿里云4核8G服务器优惠价格表,最低价格501.90元6个月、983.80元1年

阿里云4核8G服务器优惠价格表&#xff0c;云服务器ECS计算型c7实例4核8G配置3M带宽40GB ESSD云盘&#xff08;系统盘&#xff09;叠加使用优惠券后价格501.90元6个月、983.80元1年&#xff0c;现在购买经济型e、通用算力型u1、计算型c7和计算型c8a与c8i实例4核8G配置均有优惠&a…

synchronized锁膨胀过程

轻量级锁&#xff1a; 使用场景&#xff1a;如果一个对象虽然有多线程要加锁&#xff0c;但加锁的时间是错开的&#xff08;也就是没有竞争&#xff09;&#xff0c;那么可以 使用轻量级锁来优化。 轻量级锁原理 1.创建锁记录&#xff08;Lock Record&#xff09;对象&#…

IF:9.0+期刊被踢除,11月SCI/SSCI期刊目录已更新!

【SciencePub学术】2023年11月20日&#xff0c;科睿唯安更新了Web of Science核心期刊目录。 继上次SCI期刊目录和SSCI期刊目录更新之后&#xff0c;本次11月更新共有5本期刊发生变动&#xff1a; • SCIE&#xff1a;有5本期刊不再被SCIE期刊目录收录&#xff0c;1本SCIE期刊更…

infercnv 三回首:深入理解infercnv为何能发nature

大家好&#xff0c;不知你是否还记得&#xff0c;前两次关于infercnv的介绍。请看这里&#xff1a; 肿瘤单细胞转录组拷贝数分析结果解读和应用 单细胞拷贝数变异 infercnv再回首 如果下载了示例数据&#xff0c;并且你已经跑了上述代码&#xff0c;不难得到这张图&#xff1…