QT+OpenCV实现一个标注工具(图像处理、边缘检测)

这篇具有很好参考价值的文章主要介绍了QT+OpenCV实现一个标注工具(图像处理、边缘检测)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

作者是一名QT初学者,为检验学习成果及完成毕业设计,在张老师和学姐的指导下,开发了这个标注工具。CSDN上很多文章对我的学习提供了极大的帮助,分享这篇文章给需要的人一起学习进步~

废话不多说,先看看效果:

qt opencv图像识别,opencv,qt,图像处理,c++,Powered by 金山文档

开发环境

Windows10、Qt5.13.2(编译器用的是MinGW64_bit)、OpenCV4.1

开发过程

环境配置

首先,安装Qt Creator,在Qt里引入OpenCV库,需要使用CMake对库进行编译,相关环境配置具体参考了这两篇文章:

win10下Qt5.12.3配置OpenCV4.5.3

opencv编译

编译过程需要注意版本问题,版本过高编译容易出错,一些常见的错误在参考文章结尾有提到。另外在编译过程中需要下载一些文件,最好挂个梯子,不然需要自己单独去下载。

项目文件结构

qt opencv图像识别,opencv,qt,图像处理,c++,Powered by 金山文档

aboutdialog:点击帮助->关于弹出的对话框,用于简单介绍使用方法

mainwindow:程序主窗口,用于响应主窗口的点击事件及图像数据处理

mygraphicsview:显示图像的控件,用于处理用户与图像的交互事件

selectmergemapdialog:点击拆分合并->合并后弹出的对话框,用于选择需要合并的图像

Resources目前只存放了程序的图标

操作按键说明

按住鼠标右键拖动将轨迹上的点标注

按住shift键右键拖动把轨迹上的点取消标注

按住alt键右键拖曳把区域内的点取消标注

按住ctrl键右键拖曳把区域以外的点取消标注

双击左键图像复位

部分核心代码

mainwindow部分

在初始界面显示“把图片拖到此处打开”,涉及重叠控件的布局问题

//显示“把图片拖到此处打开”
QFont font("楷体",20,QFont::Bold);
welcome_label->setFont(font);
welcome_label->setText("把图片拖到此处打开");
welcome_label->setAlignment(Qt::AlignCenter);
welcome_label->setStyleSheet("color:gray;");
welcome_label->resize(260,30);
welcome_label->setGeometry(this->width()/2-welcome_label->width()/2,this->height()/2-welcome_label->height()/2,welcome_label->width(),welcome_label->height());
//将m_layout装进graphicsView,然后把welcome_label放进m_layout,设置居中对齐
m_layout = new QHBoxLayout(ui->graphicsView);
m_layout->addWidget(welcome_label);
m_layout->setAlignment(welcome_label, Qt::AlignCenter);

保存当前显示的图像,文件名设置为系统时间,如:20230323_113726.png

//设置保存路径
QString path=QCoreApplication::applicationDirPath();
path.append("/");
path.append(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
path.append(".png");
//qDebug()<<path;
QString get_save_path=QFileDialog::getSaveFileName(this,"保存当前显示图像",path);

//执行保存
if(ui->graphicsView->getPixmap().save(get_save_path)){
    QMessageBox::information(this,"提示","保存成功");
}

点击边缘检测->canny,对目标图像进行canny边缘检测。程序中设置了四个图像缓存,分别用于存储原图、变换图、滤波图、边缘检测图,依次命名为origin_img,transform_img,filted_img,edge_img,在进行任何图像处理前需要选择目标图像。

//对图像进行边缘检测并将结果显示到graphicsView中
Mat src,t,dst;
//选择图像来源,优先次序为filted_img,transform_img,origin_img
if(!filted_img.isNull()){
    t=fromImage(filted_img);
    t.copyTo(src);
}
else if(!transform_img.isNull()){
    t=fromImage(transform_img);
    t.copyTo(src);
}
else{
    t=fromImage(origin_img);
    t.copyTo(src);
}
//将目标图像转换成8位单通道灰度图
if(src.type()!=CV_8UC1){
    src.convertTo(src,CV_8UC1);
}

Canny(src,dst,ui->sliderForThreshold1->value(),ui->sliderForThreshold2->value());
QImage img=matToImage(dst);
//保存图像到缓存,注意要用深拷贝
edge_img=img.copy(0,0,img.width(),img.height());

对目标图像进行sobel边缘检测。

//先计算xy方向上的边缘检测图
Mat sobel_x,sobel_y;
Sobel(src,sobel_x,CV_64F,1,0);
Sobel(src,sobel_y,CV_64F,0,1);
convertScaleAbs(sobel_x,sobel_x);
convertScaleAbs(sobel_y,sobel_y);
//两者加权平均
addWeighted(sobel_x,0.5,sobel_y,0.5,0,dst);
//将得到的检测结果dst根据阈值进行两级化,高于阈值的像素值置为255,低于的置为0
for (int x = 0; x < dst.rows; ++x) {
    for (int y = 0; y < dst.cols; ++y) {
        if(dst.at<uchar>(x,y)>ui->sliderForBound_2->value()){
            dst.at<uchar>(x,y)=255;
        }
        else{
            dst.at<uchar>(x,y)=0;
        }
    }
}
QImage img=matToImage(dst);
//保存图像到缓存,注意要用深拷贝
edge_img=img.copy(0,0,img.width(),img.height());

对目标图像进行巴特沃斯高通滤波,算法使用C++和OpenCV实现:

Mat src,dst;
//高通滤波,增强边缘
src.convertTo(src,CV_32FC1);
Mat f_complex_c2;
//傅里叶变换
dft(src,f_complex_c2,DFT_COMPLEX_OUTPUT);

//将f_complex_c2低频区域的值归零,保留高频区域的值
//计算滤波半径,图像中心位置
int radius=f_complex_c2.cols>f_complex_c2.rows?(f_complex_c2.rows/2)*(ui->lcdHighpassRadius->value()/100.0):(f_complex_c2.cols/2)*(ui->lcdHighpassRadius->value()/100.0);
int cx=f_complex_c2.cols/2;
int cy=f_complex_c2.rows/2;
//将低频移至中心
Mat temp;
//这里用的是浅拷贝,对part图像的交换操作将影响f_complex_c2
Mat part1(f_complex_c2,Rect(0,0,cx,cy));
Mat part2(f_complex_c2,Rect(cx,0,cx,cy));
Mat part3(f_complex_c2,Rect(0,cy,cx,cy));
Mat part4(f_complex_c2,Rect(cx,cy,cx,cy));
part1.copyTo(temp);
part4.copyTo(part1);
temp.copyTo(part4);

part2.copyTo(temp);
part3.copyTo(part2);
temp.copyTo(part3);
//巴特沃斯高通滤波
for (int i = 0; i < f_complex_c2.rows; ++i) {
    for (int j = 0; j < f_complex_c2.cols; ++j) {
        f_complex_c2.at<Vec2f>(i,j)=f_complex_c2.at<Vec2f>(i,j)*(1.0-(1.0 / (1.0 + pow(sqrt(pow(i - cy, 2.0) + pow(j - cx, 2.0)) / radius, 4.0))));
    }
}
//将低频中心移回原来位置
Mat temp_;
//这里用的是浅拷贝,对part图像的交换操作将影响f_complex_c2
Mat part1_(f_complex_c2,Rect(0,0,cx,cy));
Mat part2_(f_complex_c2,Rect(cx,0,cx,cy));
Mat part3_(f_complex_c2,Rect(0,cy,cx,cy));
Mat part4_(f_complex_c2,Rect(cx,cy,cx,cy));
part1_.copyTo(temp_);
part4_.copyTo(part1_);
temp_.copyTo(part4_);

part2_.copyTo(temp_);
part3_.copyTo(part2_);
temp_.copyTo(part3_);
//傅里叶逆变换,只取实部
Mat f_real_c1;
dft(f_complex_c2,f_real_c1,DFT_REAL_OUTPUT + DFT_SCALE + DFT_INVERSE);
f_real_c1.convertTo(dst,CV_8UC1);

QImage img=matToImage(dst);
//保存图像到缓存,注意要用深拷贝
filted_img=img.copy(0,0,img.width(),img.height());

log变换。

//对图像做新的log变换
Mat src,dst;
src=fromImage(origin_img);
src.convertTo(src, CV_32FC1);  //转化为32位浮点型
src = src*value + 1;           //计算 r*v+1
log(src, src);                 //计算log(1+r*v),底数为e
src=src/log(value);//底数换成v
//归一化处理
normalize(src, dst, 0, 255, NORM_MINMAX,CV_8UC1);
//保存图像到缓存,注意要用深拷贝
QImage img=matToImage(dst);
transform_img=img.copy(0,0,img.width(),img.height());

图像合并。base_img来源于“选择合并对象”对话框的选择结果。标注颜色存储在mark_color变量中,类型为QColor,改变标注颜色即改变该变量的值,默认为紫色。

//将base_img和边缘检测图合并为merge_mat
Mat merge_mat;
vector<Mat> channels;
//将base_img转为4通道,并分离到channels
split(fromImage(base_img.convertToFormat(QImage::Format_ARGB32)),channels);
int x=base_img.width();
int y=base_img.height();
//在base_img的基础上对检测到的边缘标注紫色,紫色ARGB值为(255,255,0,255)
//注意mat和qimage的坐标关系,刚好相反
for (int i = 0; i < x; ++i) {
    for (int j = 0; j < y; ++j) {
        if(edge_img.pixel(i,j)==0xFFFFFFFF){
            channels.at(0).at<uchar>(j,i)=mark_color.blue();//B通道
            channels.at(1).at<uchar>(j,i)=mark_color.green();//G通道
            channels.at(2).at<uchar>(j,i)=mark_color.red();//R通道
        }
    }
}
merge(channels,merge_mat);
ui->graphicsView->setPixmap(matToImage(merge_mat));

右键改变标注状态的实现。

有两种思路:

  1. 获取当前显示的图像,拆分为3通道,对点击处的像素设置成紫色(标注)或恢复原来的RGB值(取消标注),重新合并3通道后显示;

  1. 对边缘检测结果图进行操作,将点击处的像素值取反(0为未标记状态,1为标记),再与合并对象进行合并,最后显示。

第二种方法比较容易实现,实现过程:

//将点击处的像素值取反
edge_img.setPixel(x,y,0x00FFFFFF ^ edge_img.pixel(x,y));

//将base_img和边缘检测图合并为merge_mat
Mat merge_mat;
vector<Mat> channels;
//将base_img转为4通道,并分离到channels
split(fromImage(base_img.convertToFormat(QImage::Format_ARGB32)),channels);
int x=base_img.width();
int y=base_img.height();
//在base_img的基础上对检测到的边缘标注紫色,紫色ARGB值为(255,255,0,255)
//注意mat和qimage的坐标关系,刚好相反
for (int i = 0; i < x; ++i) {
    for (int j = 0; j < y; ++j) {
        if(edge_img.pixel(i,j)==0xFFFFFFFF){
            channels.at(0).at<uchar>(j,i)=mark_color.blue();//B通道
            channels.at(1).at<uchar>(j,i)=mark_color.green();//G通道
            channels.at(2).at<uchar>(j,i)=mark_color.red();//R通道
        }
    }
}
merge(channels,merge_mat);
ui->graphicsView->setPixmap(matToImage(merge_mat));

按住shift键和右键移动鼠标,对轨迹附近的点取消标注。按住alt键右键拖曳,将矩形区域内的点取消标记也是这个道理。

//对(x,y)八邻域的像素取消标记
for (int i = x-1; i <= x+1; ++i) {
    for (int j = y-1; j <= y+1; ++j) {
        edge_img.setPixel(i,j,0xFF000000);
    }
}

//修改边缘检测图edge_img,将区域内的像素全部置黑,即取消标记
for (int x = lx; x <= rx; ++x) {
    for (int y = ty; y <= by; ++y) {
        edge_img.setPixel(x,y,0xFF000000);
    }
}

//将base_img和边缘检测图合并为merge_mat
Mat merge_mat;
vector<Mat> channels;
//将base_img转为4通道,并分离到channels
split(fromImage(base_img.convertToFormat(QImage::Format_ARGB32)),channels);
int x=base_img.width();
int y=base_img.height();
//在base_img的基础上对检测到的边缘标注紫色,紫色ARGB值为(255,255,0,255)
//注意mat和qimage的坐标关系,刚好相反
for (int i = 0; i < x; ++i) {
    for (int j = 0; j < y; ++j) {
        if(edge_img.pixel(i,j)==0xFFFFFFFF){
            channels.at(0).at<uchar>(j,i)=mark_color.blue();//B通道
            channels.at(1).at<uchar>(j,i)=mark_color.green();//G通道
            channels.at(2).at<uchar>(j,i)=mark_color.red();//R通道
        }
    }
}
merge(channels,merge_mat);
ui->graphicsView->setPixmap(matToImage(merge_mat));
mygraphicsview部分

该部分用于处理用户与图像的交互事件,当捕捉到用户操作后,释放信号交由mainwindow处理

拖动图片到窗口打开需要重写dragEnterEventdropEvent事件

void MyGraphicsView::dragEnterEvent(QDragEnterEvent *event)
{
    //如果拖进窗口的文件类型是png、jpg、bng,接受这类文件
    if(!event->mimeData()->urls()[0].fileName().right(3).compare("png")||!event->mimeData()->urls()[0].fileName().right(3).compare("jpg")||!event->mimeData()->urls()[0].fileName().right(3).compare("bng")){
        event->accept();
    }
    else{
        event->ignore();//否则不接受鼠标事件
    }

    QGraphicsView::dragEnterEvent(event);
}

void MyGraphicsView::dropEvent(QDropEvent *event){
    //从event中获取文件路径
    const QMimeData *data=event->mimeData();
    //向主窗口传递信号
    QString file_name=data->urls()[0].toLocalFile();
    emit dragFile(file_name);

    QGraphicsView::dropEvent(event);
}

滚动滑轮进行缩放,重写wheelEvent事件

void MyGraphicsView::zoom(qreal factor)
{
    //防止缩得太小或放得太大
    qreal t = transform().scale(factor, factor).mapRect(QRectF(0, 0, 1, 1)).width();
    if (t < 0.07 || t > 100)
        return ;

    scale(factor, factor);
}

//当滑轮滚动时触发该函数,进行图像缩放
void MyGraphicsView::wheelEvent(QWheelEvent *event)
{
    //当滑轮滚动时,获取其滚动量
    QPoint amount=event->angleDelta();
    //正值表示放大,负值表示缩小
    amount.y()>0?zoom(1.1):zoom(0.9);
}

还有重写mousePressEventmouseMoveEventmouseReleaseEvent事件以实现各种快捷键操作

//当鼠标按下时触发该函数
void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{
    //如果按下左键,选中标记置true,同时记录按下位置
    if(event->button()==Qt::LeftButton){
        isSelected=true;
        currentPoint=event->globalPos();
    }
    //如果按下shift键后按下右键,并且当前图像经过边缘检测处理,可能做的是将鼠标划过的点取消标注的操作
    else if(event->modifiers() == Qt::ShiftModifier && event->button()==Qt::RightButton && isProcessed){
        remove_points=true;
        //标记右键被按下
        this->rightbuttonIsPressed=true;
    }
    //如果按下alt键后按下右键,并且当前图像经过边缘检测处理,可能做的是将拖曳区域内的点取消标注的操作
    else if(event->modifiers() == Qt::AltModifier && event->button()==Qt::RightButton && isProcessed){
        delete_points=true;
        //标记右键被按下
        this->rightbuttonIsPressed=true;
        //记录右键按下位置
        this->start=mapToScene(event->pos());
    }
    //如果按下ctrl键后按下右键,并且当前图像经过边缘检测处理,可能做的是保留拖曳区域内点的操作
    else if(event->modifiers() == Qt::ControlModifier && event->button()==Qt::RightButton && isProcessed){
        reserve_points=true;
        //标记右键被按下
        this->rightbuttonIsPressed=true;
        //记录右键按下位置
        this->start=mapToScene(event->pos());
    }
    //如果按下右键,并且当前图像经过边缘检测处理
    else if(event->button()==Qt::RightButton && isProcessed){
        //标记右键被按下
        this->rightbuttonIsPressed=true;
        //记录右键按下位置
        this->start=mapToScene(event->pos());
    }
    QGraphicsView::mousePressEvent(event);
}

//当鼠标移动时触发该函数
void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    //当鼠标左键在按住状态下移动时,计算光标偏移量(这里不能用event->button()==Qt::LeftButton)
    if(isSelected){
        QPoint offset=event->globalPos()-currentPoint;
        currentPoint=event->globalPos();
        //移动窗口实现图片拖动效果,但拖动图像时会出现图像偏移的情况,有时又正常,一直想不明白原因,这个地方有待研究改进
        int x=(width()-1)/2-offset.x();
        int y=(height()-1)/2-offset.y();
        centerOn(mapToScene(x,y));
    }

    QPointF p=mapToScene(event->pos());
    int x=p.x();
    int y=p.y();
    //如果鼠标在显示图像内,释放信号,传递坐标
    if(!pixmapItem->pixmap().isNull()){
        int width=pixmapItem->pixmap().width();
        int height=pixmapItem->pixmap().height();
        //不能用0<=x<width
        if(x>=0 && x<width && y>=0 &&y<height){
            emit mouseMove(x,y);
            //同时当鼠标右键在按住状态下移动时,对轨迹上的点进行标注
            if(rightbuttonIsPressed&&!delete_points&&!reserve_points&&!remove_points){
                emit mouseMoveWithRightButton(x,y);
            }
            //当鼠标右键和shift被按下,鼠标移动过程中对轨迹上的点取消标注
            else if(remove_points){
                emit mouseMoveWithRightButtonAndShift(x,y);
            }
        }
    }

    QGraphicsView::mouseMoveEvent(event);
}

//当鼠标松开时,选中标记置false
void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton){
        isSelected=false;
    }
    //如果松开的是右键,并且当前图像经过边缘检测处理
    else if(event->button()==Qt::RightButton && isProcessed){
        //右键松开
        this->rightbuttonIsPressed=false;
        //记录右键松开的位置
        QPointF end=mapToScene(event->pos());
        //两者做差
        QPointF offset=end-start;
        //如果做的是拖曳消除区域点的操作
        if(qAbs(offset.x())>=1||qAbs(offset.y())>=1){
            //获取区域左上角和右下角的坐标
            int larger_x,smaller_x,larger_y,smaller_y;
            end.x()>start.x()?larger_x=end.x():larger_x=start.x();
            end.x()>start.x()?smaller_x=start.x():smaller_x=end.x();
            end.y()>start.y()?larger_y=end.y():larger_y=start.y();
            end.y()>start.y()?smaller_y=start.y():smaller_y=end.y();
            //将区域约束到图像内
            if(smaller_x<0)smaller_x=0;
            if(smaller_x>pixmapItem->pixmap().width()-1)smaller_x=pixmapItem->pixmap().width()-1;
            if(larger_x<0)larger_x=0;
            if(larger_x>pixmapItem->pixmap().width()-1)larger_x=pixmapItem->pixmap().width()-1;
            if(smaller_y<0)smaller_y=0;
            if(smaller_y>pixmapItem->pixmap().height()-1)smaller_y=pixmapItem->pixmap().height()-1;
            if(larger_y<0)larger_y=0;
            if(larger_y>pixmapItem->pixmap().height()-1)larger_y=pixmapItem->pixmap().height()-1;
            //释放信号交由主窗口处理
            if(reserve_points){
                reserve_points=false;
                emit rightButtonDragCtrl(smaller_x,smaller_y,larger_x,larger_y);
            }
            else if(delete_points){
                delete_points=false;
                emit rightButtonDrag(smaller_x,smaller_y,larger_x,larger_y);
            }
            else if(remove_points){
                remove_points=false;
            }
        }
        //否则做的是标注点的操作
        else{
            //释放信号交由主窗口处理
            emit rightButtonClick(end.x(),end.y());
        }
    }
    QGraphicsView::mouseReleaseEvent(event);
}

存在问题

鼠标左键拖动图像时会出现图像偏移现象,即鼠标指针没有固定到图像的某点上,但在某些情况下又是正常的,具体效果如下:

异常(拖动前后指针不在同一点)

qt opencv图像识别,opencv,qt,图像处理,c++,Powered by 金山文档

正常(拖动前后指针在同一点)

qt opencv图像识别,opencv,qt,图像处理,c++,Powered by 金山文档

拖动效果在mouseMoveEvent中实现,在代码中也有相应注释,欢迎各位大佬指正

上述问题已得到解决。

github地址:https://github.com/FonlinGH/MarkupTool,包含源代码及可执行程序

第一次写博客,有不恰当的地方还请谅解,仅用作学习记录。

参考文章链接:

win10下Qt5.12.3配置OpenCV4.5.3

qt5配置msvc2017

opencv编译

Opencv图像增强算法实现

OpenCV像增强之对数变换log

OPENCV Mat的数据类型

QGraphicsView图形视图框架使用(一)坐标变换

QGraphicsView教程文章来源地址https://www.toymoban.com/news/detail-678252.html

到了这里,关于QT+OpenCV实现一个标注工具(图像处理、边缘检测)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【OpenCV实现图像:使用OpenCV进行图像处理之透视变换】

    透视变换(Perspective Transformation)是一种图像处理中常用的变换手段,它用于将图像从一个视角映射到另一个视角,常被称为投影映射。透视变换可以用于矫正图像中的透视畸变,使得图像中的物体在新的视平面上呈现更加规则的形状。 透视变换通常涉及到寻找图像中的特定

    2024年02月03日
    浏览(64)
  • 【OpenCV实现平滑图像处理】

    在图像处理中,低通滤波器是一种常用的技术,用于平滑、模糊或降低图像的噪音。这种滤波器通过去除图像中高频部分(即变化较快的部分)来实现这些效果。通过应用2D卷积操作,低通滤波器将每个像素的值与其周围像素的值进行加权平均,从而实现图像的平滑处理。 在

    2024年02月08日
    浏览(39)
  • 图像处理--OpenCV实现图像加噪与滤波

    前言: Hello大家好,我是Dream。 今天来学习一下如何使用OpenCV实现图像加噪与滤波,欢迎大家一起参与探讨交流~ 编写一Python程序,要求实现以下功能: 读入一幅图像。 使用两种以上的方法分别向图像中添加噪声。 输出一幅二值图像,图像中未加入噪声的区域为黑色,加入

    2024年02月03日
    浏览(37)
  • 图像处理之DCT图像压缩(基于c++ opencv实现)

    是老师布置的作业,拖到ddl才开始,opencv也才刚接触,有自己结合百度的一点理解,如有误,请谅解! 先贴一段在matlab上实现的代码,这个在网上都可以查到,就不赘述了 思路如下:      先划分处理块大小,对每个块分别进行DCT变换,再舍弃每个块中的高频系数,再进行

    2024年02月09日
    浏览(69)
  • 【图像处理】看OpenCV如何实现相机校准

            在本教程中,将介绍计算机视觉的科学领域,以及相机校准过程的简要总结。计算机视觉是实现自主系统的尝试,这些系统可以实现“人类视觉”的某些功能,其中相机被认为是传感器之一(相当于人眼)。了解捕获图像的内容是一项关键任务,这些计算机视觉系

    2024年02月12日
    浏览(37)
  • 选择最佳图像处理工具OpenCV、JAI、ImageJ、Thumbnailator和Graphics2D

        SVD(stable video diffusion)开放了图生视频的API,但是限制图片分辨率必须为下面三种 1024x576 、 576x1024 、 768x768 。项目基于Fooocus生成的图片分辨率不满足,然后基于ImageIO+Graphics2D处理了一下,修改图片分辨率,然后再去生成视频。功能调通了,但是发现图片清晰度严重下降

    2024年03月27日
    浏览(45)
  • 基于opencv的图像处理系统的设计与实现

      随着计算机技术的飞速发展,图像技术在各领域的研究和应用日渐深入和广泛。opencv是近年来推出的开源、免费的计算机视觉库,利用其所包含的函数可以很方便地实现数字图像处理。本文旨在对opencv进行一个快速全面简介,通过介绍图像处理的相关函数,使读者能快速形

    2024年04月27日
    浏览(39)
  • Python调用OpenCV实现图像反色(反相)处理

    1 前言 上一篇介绍了用C++如何将一幅彩色图像和灰度图像进行反色处理,本篇接着用python来做同样的事情。 图像反转,其目的就是增强图像的暗区中白色或灰色的细节,特别是原图中的阴影黑色区域。 原理就是用值 255 减去原来像素点上的像素值 ,比如用255(白色)-0(黑色

    2024年02月07日
    浏览(42)
  • 【图像处理软件】Pyqt5+OpenCV实现图像的处理(附可视化界面+功能介绍+源代码)

    1.前言        使用pyqt5与opencv实现的图像处理程序,已实现转灰度图、图像平滑、形态学操作、梯度计算、阈值处理、边缘检测、轮廓检测等功能。 ☘️ Pyqt5介绍: Pyqt5是基于Digia公司强大的图形程式框架Qt5的python接口,由一组python模块构成。Pyqt5本身拥有超过620个类和600

    2024年02月08日
    浏览(73)
  • 基于 OpenCV 的图像处理与分析应用的设计与实现

    图像处理与分析是计算机视觉中的重要应用领域,通过对图像进行处理和分析,可以提取有用的信息和特征,用于解决实际问题。 OpenCV 是一个强大的开源计算机视觉库,提供了丰富的功能和算法,适用于各种图像处理和分析任务。本文将以设计和实现一个基于 OpenCV 的图像处

    2024年02月16日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包