【数字图像处理】图像形态学算法C语言实现(图像卷积,膨胀,腐蚀,开运算,闭运算,顶帽,黑帽,雕版,锐化)

2023-11-17

(一)图像卷积

1. 图像卷积

图像卷积是进行空间域滤波与梯度运算的基础。首先我们需要理解卷积的运算方式从而可以编程实现。

2. 数字信号处理中的卷积

卷积一词最开始出现在信号与线性系统中,信号与线性系统中讨论的就是信号经过一个线性系统以后发生的变化。由于现实情况中常常是一个信号前一时刻的输出影响着这一时刻的输出,所在一般利用系统的单位响应与系统的输入求卷积,以求得系统的输出信号(当然要求这个系统是线性时不变的)。
卷积的定义:
卷积是两个变量在某范围内相乘后求和的结果。如果卷积的变量是序列x(n)和h(n),则卷积的结果:
在这里插入图片描述

3 数字图像处理中的卷积

数字图像是一个二维的离散信号,对数字图像做卷积操作其实就是利用卷积核(卷积模板)在图像上滑动,将图像点上的像素灰度值与对应的卷积核上的数值相乘,然后将所有相乘后的值相加作为卷积核中间像素对应的图像上像素的灰度值,并最终滑动完所有图像的过程。
在这里插入图片描述

图表 3
这张图可以清晰的表征出整个卷积过程中一次相乘后相加的结果:该图片选用3*3的卷积核,卷积核内共有九个数值,所以图片右上角公式中一共有九行,而每一行都是图像像素值与卷积核上数值相乘,最终结果-8代替了原图像中对应位置处的1。这样沿着图片一步长为1滑动,每一个滑动后都一次相乘再相加的工作,我们就可以得到最终的输出结果。除此之外,卷积核的选择有一些规则:
(1)卷积核的大小一般是奇数,这样的话它是按照中间的像素点中心对称的,所以卷积核一般都是3x3,5x5或者7x7。有中心了,也有了半径的称呼,例如5x5大小的核的半径就是2。
(2)卷积核所有的元素之和一般要等于1,这是为了原始图像的能量(亮度)守恒。其实也有卷积核元素相加不为1的情况,下面就会说到。
(3)如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。
(4)对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截断到0和255之间即可。对于负数,也可以取绝对值。

(二)图像卷积实现各种形态学运算

腐蚀

极小值卷积,求局部极小值

膨胀

极大值卷积,求局部极大值

形态学梯度

开运算

闭运算

顶帽

黑帽

雕版

锐化

li_conv.c

/*
 * @Descripttion: 
 * @version: 
 * @Author: Yueyang
 * @email: 1700695611@qq.com
 * @Date: 2020-11-10 21:59:39
 * @LastEditors: Yueyang
 * @LastEditTime: 2020-11-24 21:15:30
 */
#ifndef LI_CONV_C
#define LI_CONV_C



#include "cv.h"
#include "li_image_proc.h"
#include <stdio.h>


/**
 * @name: Li_GetKernel
 * @msg:  得到卷积核矩阵
 * @param {double* data 数据
 *         BYTE KernalKind 卷积核边长}
 * @return {Li_Kernel*}
 */
LI_API 
Li_Kernel* Li_GetKernel(double* data,BYTE KernalKind)
{
    Li_Kernel * kernel;
    kernel=(Li_Kernel*)li_malloc_arr(sizeof(Li_Kernel));
    kernel->arr=(double*)li_malloc_arr(KernalKind*KernalKind*sizeof(double));
    for(int i=0;i<KernalKind*KernalKind;i++)
    kernel->arr[i]=data[i];
    kernel->width=KernalKind;
    kernel->height=KernalKind;
    kernel->arrsize=KernalKind*KernalKind;
    return kernel;
}

/**
 * @name: Li_Convolute
 * @msg: 计算图像卷积
 * @param {Li_Image* img 卷积图像
 *         Li_Kernel* kernal 卷积核 }
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Convolute(Li_Image* img,Li_Kernel* kernal)
{
  if(img->imgdepth==LI_DEP_8U){
    if(kernal->width!=3) return NULL;
    BYTE* ptr[9]={0};
    BYTE* ptro;
    Li_Image* out=Li_Copy_Image(img);
    for(int i=0;i<img->height;i++)
        for(int j=0;j<img->width;j++)
        {
             BYTE sum=0;
             if(j-1>=0&&i-1>=0)
             ptr[0]=(BYTE*)img->at(img,j-1,i-1);
             if(j>=0&&i-1>=0)
             ptr[1]=(BYTE*)img->at(img,j+0,i-1);
             if(j+1<=img->width&&i-1>=0)
             ptr[2]=(BYTE*)img->at(img,j+1,i-1);
             if(j-1>=0&&i>=0)
             ptr[3]=(BYTE*)img->at(img,j-1,i+0);
             if(j>=0&&i>=0)
             ptr[4]=(BYTE*)img->at(img,j+0,i+0);
             if(j+1<=img->width&&i>=0)
             ptr[5]=(BYTE*)img->at(img,j+1,i+0);
             if(j-1>=0&&i+1<=img->height)
             ptr[6]=(BYTE*)img->at(img,j-1,i+1);
             if(j>=0&&i+1<=img->height)
             ptr[7]=(BYTE*)img->at(img,j+0,i+1);
             if(j+1<=img->width&&i+1<=img->height)
             ptr[8]=(BYTE*)img->at(img,j+1,i+1);
            for(int k=0;k<9;k++)
            {
                double* ptr2=(double*)(kernal->arr+k);
                if(ptr[k]!=NULL)
                {
                    sum+= (BYTE)(*ptr[k] * (*ptr2));
                }
                else 
                {
                    sum+=0;
                }
            }
            ptro=(BYTE*)out->at(out,j+0,i+0);
            *ptro=sum;
        }
        return out;
  }else if (img->imgdepth==LI_DEP_24U||img->imgdepth==LI_DEP_32U)
  {
     Li_Image* imgH[img->imgdepth+1];
     Li_Image* imgL[img->imgdepth+1];
     Li_Split(img,imgH);
     for(int i=0;i<img->imgdepth+1;i++)
     imgL[i]= Li_Convolute(imgH[i],kernal);     
     Li_Image* out2=Li_Combine(imgL,img->imgdepth);
     return out2;
  }
}


/**
 * @name: Li_Sharp
 * @msg:  图像锐化
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Sharp(Li_Image* img)
{
    double data[9]={1,1,1,1,-7,1,1,1,1}; 
    if(img==NULL)return NULL;
    if(img->imgdepth==LI_DEP_8U){
        Li_Image* out;
        Li_Kernel* kernel;

        kernel=Li_GetKernel(data,3);
        out= Li_Convolute(img,kernel);
        return out;
    }else if (img->imgdepth==LI_DEP_24U||img->imgdepth==LI_DEP_32U)
    {
        Li_Image* imgH[img->imgdepth+1];
        Li_Image* imgL[img->imgdepth+1];
        Li_Split(img,imgH);
        for(int i=0;i<img->imgdepth+1;i++)  
        {
            imgL[i]=Li_Sharp(imgH[i]);
        }
        Li_Image* out2=Li_Combine(imgL,img->imgdepth);
        return out2;
    }
}

/**
 * @name: Li_Emboss
 * @msg:  图像雕版
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Emboss(Li_Image* img)
{
    double data[9]={0,0,-1,0,-1,0,2,0,0}; 
    if(img==NULL)return NULL;
    if(img->imgdepth==LI_DEP_8U){
        Li_Image* out;
        Li_Kernel* kernel;

        kernel=Li_GetKernel(data,3);
        out= Li_Convolute(img,kernel);
        return out;
    }else if (img->imgdepth==LI_DEP_24U||img->imgdepth==LI_DEP_32U)
    {
        Li_Image* imgH[img->imgdepth+1];
        Li_Image* imgL[img->imgdepth+1];
        Li_Split(img,imgH);
        for(int i=0;i<img->imgdepth+1;i++)  
        {
            imgL[i]=Li_Emboss(imgH[i]);
        }
        Li_Image* out2=Li_Combine(imgL,img->imgdepth);
        return out2;
    }
}


/**
 * @name: Li_Erode
 * @msg: 图像腐蚀(局部最小)
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Erode(Li_Image* img)
{
  if(img->imgdepth==LI_DEP_8U){
    BYTE kek=0;
    BYTE* ptr[9]={0};
    BYTE* ptro;
    Li_Image* out=Li_Copy_Image(img);
    for(int i=0;i<img->height;i++)
        for(int j=0;j<img->width;j++)
        {
             BYTE sum=0;
             for(int k=0;k<9;k++)
             ptr[k]=&kek;
             
             if(j-1>=0&&i-1>=0)
             ptr[0]=(BYTE*)img->at(img,j-1,i-1);
             if(j>=0&&i-1>=0)
             ptr[1]=(BYTE*)img->at(img,j+0,i-1);
             if(j+1<=img->width&&i-1>=0)
             ptr[2]=(BYTE*)img->at(img,j+1,i-1);
             if(j-1>=0&&i>=0)
             ptr[3]=(BYTE*)img->at(img,j-1,i+0);
             if(j>=0&&i>=0)
             ptr[4]=(BYTE*)img->at(img,j+0,i+0);
             if(j+1<=img->width&&i>=0)
             ptr[5]=(BYTE*)img->at(img,j+1,i+0);
             if(j-1>=0&&i+1<=img->height)
             ptr[6]=(BYTE*)img->at(img,j-1,i+1);
             if(j>=0&&i+1<=img->height)
             ptr[7]=(BYTE*)img->at(img,j+0,i+1);
             if(j+1<=img->width&&i+1<=img->height)
             ptr[8]=(BYTE*)img->at(img,j+1,i+1);
            
            BYTE temp[9];
            for(int k=0;k<9;k++)
            {
                if(ptr[k]!=NULL)
                {
                    temp[k]= (BYTE)(*ptr[k]);
                }
            }
            for(int m=0;m<9-1;m++)
                for(int n=0;n<9-m-1;n++)
                {
                    if(temp[m]>temp[m+1])
                    {
                        BYTE x=temp[m];
                        temp[m]=temp[n+1];
                        temp[n+1]=x;
                    }
                }
           ptro=(BYTE*)out->at(out,j+0,i+0);
           *ptro=temp[0];
        }
        return out;
  }else if (img->imgdepth==LI_DEP_24U||img->imgdepth==LI_DEP_32U)
  {
     Li_Image* imgH[img->imgdepth+1];
     Li_Image* imgL[img->imgdepth+1];
     Li_Split(img,imgH);
     for(int i=0;i<img->imgdepth+1;i++)
     imgL[i]= Li_Medeum(imgH[i]);     
     Li_Image* out2=Li_Combine(imgL,img->imgdepth);
     return out2;
  }
}


/**
 * @name: Li_Dilate
 * @msg: 图像膨胀(局部最小)
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Dilate(Li_Image* img)
{
  if(img->imgdepth==LI_DEP_8U){
    BYTE kek=0;
    BYTE* ptr[9]={0};
    BYTE* ptro;
    Li_Image* out=Li_Copy_Image(img);
    for(int i=0;i<img->height;i++)
        for(int j=0;j<img->width;j++)
        {
             BYTE sum=0;
             for(int k=0;k<9;k++)
             ptr[k]=&kek;
             
             if(j-1>=0&&i-1>=0)
             ptr[0]=(BYTE*)img->at(img,j-1,i-1);
             if(j>=0&&i-1>=0)
             ptr[1]=(BYTE*)img->at(img,j+0,i-1);
             if(j+1<=img->width&&i-1>=0)
             ptr[2]=(BYTE*)img->at(img,j+1,i-1);
             if(j-1>=0&&i>=0)
             ptr[3]=(BYTE*)img->at(img,j-1,i+0);
             if(j>=0&&i>=0)
             ptr[4]=(BYTE*)img->at(img,j+0,i+0);
             if(j+1<=img->width&&i>=0)
             ptr[5]=(BYTE*)img->at(img,j+1,i+0);
             if(j-1>=0&&i+1<=img->height)
             ptr[6]=(BYTE*)img->at(img,j-1,i+1);
             if(j>=0&&i+1<=img->height)
             ptr[7]=(BYTE*)img->at(img,j+0,i+1);
             if(j+1<=img->width&&i+1<=img->height)
             ptr[8]=(BYTE*)img->at(img,j+1,i+1);
            
            BYTE temp[9];
            for(int k=0;k<9;k++)
            {
                if(ptr[k]!=NULL)
                {
                    temp[k]= (BYTE)(*ptr[k]);
                }
            }
            for(int m=0;m<9-1;m++)
                for(int n=0;n<9-m-1;n++)
                {
                    if(temp[m]>temp[m+1])
                    {
                        BYTE x=temp[m];
                        temp[m]=temp[n+1];
                        temp[n+1]=x;
                    }
                }
           ptro=(BYTE*)out->at(out,j+0,i+0);
           *ptro=temp[8];
        }
        return out;
  }else if (img->imgdepth==LI_DEP_24U||img->imgdepth==LI_DEP_32U)
  {
     Li_Image* imgH[img->imgdepth+1];
     Li_Image* imgL[img->imgdepth+1];
     Li_Split(img,imgH);
     for(int i=0;i<img->imgdepth+1;i++)
     imgL[i]= Li_Medeum(imgH[i]);     
     Li_Image* out2=Li_Combine(imgL,img->imgdepth);
     return out2;
  }
}

/**
 * @name: Li_Grandient
 * @msg: 形态学梯度
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_Grandient(Li_Image* img)
{
    Li_Image* erode=Li_Erode(img);
    Li_Image* dilate=Li_Dilate(img);
    Li_Image* minus=Li_Minus(dilate,erode);
    Li_Destroy_Image(erode);
    Li_Destroy_Image(dilate);
    return minus;
}

/**
 * @name: Li_Mod_Open
 * @msg: 形态学开运算
 * @param {Li_Image* img}
 * @return {Li_Image* }
 */
LI_API
Li_Image* Li_Mod_Open(Li_Image* img)
{
    Li_Image* dilate=Li_Dilate(img);//先膨胀
    Li_Image* erode=Li_Erode(dilate);//先腐蚀
    Li_Destroy_Image(dilate);
    return erode;
}

/**
 * @name: Li_Mod_Close
 * @msg: 形态学闭运算
 * @param {Li_Image* img}
 * @return {Li_Image* }
 */
LI_API
Li_Image* Li_Mod_Close(Li_Image* img)
{
    Li_Image* erode=Li_Erode(img);//先腐蚀
    Li_Image* dilate=Li_Dilate(erode);//先膨胀
    Li_Destroy_Image(erode);
    return dilate;
}

/**
 * @name: Li_TopHat
 * @msg: 图像顶帽运算
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_TopHat(Li_Image* img)
{
    Li_Image* open=Li_Mod_Open(img);
    Li_Image* top=Li_Minus(img,open);
    Li_Destroy_Image(open);
    return top;
}

/**
 * @name: Li_BlackHat
 * @msg: 图像黑帽运算
 * @param {Li_Image* img}
 * @return {Li_Image*}
 */
LI_API
Li_Image* Li_BlackHat(Li_Image* img)
{
    Li_Image* close=Li_Mod_Close(img);
    Li_Image* black=Li_Minus(img,close);
    Li_Destroy_Image(close);
    return black;
}

#endif // !LI_CONV_C

main.c

/*
 * @Descripttion: 图像卷积常见操作
 * @version: 
 * @Author: Yueyang
 * @email: 1700695611@qq.com
 * @Date: 2020-10-26 19:35:49
 * @LastEditors: Yueyang
 * @LastEditTime: 2020-11-24 21:12:04
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "bmp.h"
#include "cv.h"
#include "li_image.h"
#include "li_painter.h"
#include "li_image_proc.h"

int main()
{
     BYTE* ptr=NULL;
     Li_Image* out =Li_Load_Image("./picture/whu_rgb888.bmp",LI_BMP_888);
     Li_Image* sharp=Li_Sharp(out);//图像锐化
     Li_Image* emboss=Li_Emboss(out);//雕版
     
     Li_Image* gray=Li_Convert_Image(out,LI_BMP_888_2_LI_BMP_8);
     Li_Image* bw  =Li_Threshold(gray,127);
     Li_Image* erode=Li_Erode(gray);//图像腐蚀
     Li_Image* dilate=Li_Dilate(gray);//图像膨胀
     Li_Image* add   =Li_Add(out,out);
     Li_Image* minus =Li_Minus(out,out);
     Li_Image* grand =Li_Grandient(gray);
     Li_Image* open  =Li_Mod_Open(gray);
     Li_Image* close =Li_Mod_Close(gray);
     Li_Image* top   =Li_TopHat(gray);
     Li_Image* black =Li_BlackHat(gray);

     Li_Image* noise =Li_Salt_Noise(out,1000);//椒盐噪声
     Li_Image* med =Li_Smooth(noise,Li_MEDIUM);//中值滤波
     Li_Image* conv=Li_Smooth(noise,Li_GAUSS);//高斯滤波
     Li_Image* ave=Li_Smooth(noise,Li_AVERAGE);//均值滤波

     Li_Save_Image("conv.bmp",conv);
     Li_Save_Image("sharp.bmp",sharp);
     Li_Save_Image("emboss.bmp",emboss);   
     Li_Save_Image("erode.bmp",erode); 
     Li_Save_Image("dilate.bmp",dilate);
     Li_Save_Image("gray.bmp",gray);
     Li_Save_Image("med.bmp",med); 
     Li_Save_Image("ave.bmp",ave); 
     Li_Save_Image("noise.bmp",noise);
     Li_Save_Image("add.bmp",add);
     Li_Save_Image("minus.bmp",minus);
     Li_Save_Image("grand.bmp",grand);
     Li_Save_Image("open.bmp",open);
     Li_Save_Image("close.bmp",close);
     Li_Save_Image("top.bmp",top);
     Li_Save_Image("black.bmp",black);
     LILOG("over");
     return 0; 
}

 

(三)效果展示

原图

在这里插入图片描述

腐蚀

在这里插入图片描述

膨胀

在这里插入图片描述

形态学梯度

在这里插入图片描述

开运算

在这里插入图片描述

闭运算

在这里插入图片描述

顶帽

在这里插入图片描述

黑帽

在这里插入图片描述

雕版

在这里插入图片描述

锐化

在这里插入图片描述

(四)写在后面

因为LiteCV项目才刚刚写了一个开头,代码中有错误的地方还望指出。我已经将项目同步到了github,我会实时更新这个代码仓库。
项目github地址:
LiteCV

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【数字图像处理】图像形态学算法C语言实现(图像卷积,膨胀,腐蚀,开运算,闭运算,顶帽,黑帽,雕版,锐化) 的相关文章

  • Servlet+JSP+JavaBean开发模式(MVC)介绍

    好伤心 写登陆注册之前看见一篇很好的博文 没有收藏 然后找不到了 前几天在知乎上看见一个问题 什么时候感觉最无力 前两天一直想回答 尝试过google到的所有solve case 结果bug依然在 今天想回答 明明遇见过 就是找不到那篇文的

随机推荐

  • 深度学习 卷积神经网络即插即用的小插件

    卷积神经网络即插即用的小插件 前言 卷积神经网络设计技巧 小插件 STN ASPP Non local SE CBAM DCN v1 v2 BlurPool RFB ASFF 代码实现 前言 本篇博客主要介绍卷积神经网络中的即插即用的模块
  • Python日志库logging总结(最全的版本)

    转自 https cloud tencent com developer article 1354396 1 日志级别 Python 标准库 logging 用作记录日志 默认分为六种日志级别 括号为级别对应的数值 NOTSET 0 DEB
  • (前端)HTML之表格

    表格标签 table 的基本语法 table 表格容器tr 列td 单元格th 粗体caption 标题列 例子 table width 400 border 1 cellspacing 2 cellpadding 2 align left
  • python中两种getter和setter方法

    当给属性赋值的时候 使用实例 属性 属性值的方式显然把属性暴露出来了 并且也无法对属性值进行限制检查 java中提供了setter和getter方法 那么python是如何做的呢 在绑定属性时 如果我们直接把属性暴露出去 虽然写起来很简单
  • 【指针内功修炼】函数指针 + 函数指针数组 + 回调函数(二)

    文章目录 1 函数指针 2 函数指针数组 函数指针数组的用途 3 指向函数指针数组的指针 4 回调函数 冒泡排序 qsort 排序 qsort 排序整型数组 qsort 排序结构体 模拟实现 qsort 1 函数指针 函数指针 顾名思义 就
  • List转换为String

    public static void main String args List
  • JBOSS实践一:安装

    因为工作关系 需要接受一套基于JBOSS容器的应用 首先从JBOSS环境搭建开始 JBOSS环境可以在一台机器上运行 也可以在一台机器上部署多套JBOSS 一 目标 1 在一台机器上部署JBOSS 4 2 2 GA 原系统运行于此 2 在一
  • Ubuntu18.04安装pcl(过程/坑记录式教程)

    Ubuntu18 04安装pcl 1 下载pcl 2 安装依赖项 3 编译 4 安装 5 网上教程说要安装QT5和VTK 但按照本文的 本文记录了安装时出现的问题 出错的安装命令也记录了 建议浏览一遍再参考 不要错用了错误的指令 1 下载p
  • background属性介绍

    background属性在CSS中有较多的应用 主要用来设置背景颜色 图片 background属性可以分开写 也可以合并 建议合并减少代码量 1 background color 设置背景颜色 设置的背景颜色会填充元素的内容 内边距和边框
  • 【SpringBoot笔记39】SpringBoot + SockJS + Stomp实现WebSocket通信(建立连接、发送消息、订阅消息、断开连接)

    这篇文章 主要介绍SpringBoot SockJS Stomp实现WebSocket通信 建立连接 发送消息 订阅消息 断开连接 目录 一 WebSocket通信 1 1 前端环境 1 2 后端环境 1 3 添加WebSocket配置
  • 传统程序优化与终身程序优化

    传统程序优化示例一 cpu示例 3个方面浅谈程序优化 每一个程序员都有一个大梦想当初在学校实验室的时候 常常写一个算法 让程序跑着四处去晃荡一下回来 结果也就出来了 可工作后 算法效率似乎重要多了 毕竟得真枪实弹放到产品中 卖给客户的 很多
  • uni-app,文本实现展开、收起全文

    效果 思路 1 根据文本显示的布局中 每行大致能显示的文字个数 实例是大致每行26个文字 2 首先加载页面时 根据文字总长度判断是否超出自定义行数 来处理相应的数据 多余自定义行数 截取对应的文字个数做显示 代码与讲解 1 设置参数 scr
  • 【Docker】Docker快速入门,常用网址与常用命令

    目录 一 docker常用网址 建议收藏 docker官方公开库 Docker Hub docker官方网站 Home Docker docker菜鸟联盟教程 Docker 教程 菜鸟教程 二 docker常用命令 一 镜像使用 1 镜像操
  • Mastering Debugging in Visual Studio 2010 - A Beginner's Guide

    Mastering Debugging in Visual Studio 2010 A Beginner s Guide http www codeproject com Articles 79508 Mastering Debugging
  • 非常好用的自动化运维工具------ansible

    目录 一 ansible 简介 1 ansible 是什么 2 ansible 特点 3 ansible 架构图 二 ansible的配置部署 1 使用 yum 安装epel源和ansible 2 修改ansible的仓库文件 3 配置公私
  • 一图看懂 Unity函数执行顺序/Unit脚本生命周期

    温故而知新 有些函数过久了忘了调用顺序 发个文记一下 下边有对各个函数的解释 第一个场景加载 这些函数在场景开始时被调用 场景中的每个对象一次 Awake 这个函数总是在任何 Start 函数之前调用 也只是在一个预制件被实例化 如果游戏对
  • 二叉树交换左右子树的三种实现方式

    二叉树交换左右子树的三种实现方式 顺序存储结构 链式存储结构 顺序存储结构 交换左右子树实际上就是同层之间交换位置 在顺序存储结构下 先确定树的深度 再划分层 每个层内做交换即可 链式存储结构 递归实现很简单 非递归可以借助栈或队列辅助实现
  • 区块链数据库

    大家好 这里是链客区块链技术问答社区 链客 有问必答 区块链是互联网未来十年中举足轻重的技术 区块链 Blockchain 或者说分布式账本 DLT Distributed Ledger Technology 最早是起源于比特币的一个重要概
  • ruoyi框架时间范围range增加今日,近7日,近30日时间选择

    原先layui时间控件是不支持今日 近7日 近30日选择的 网上的解决方法是直接在引用的js中修改代码 这是一种方法 但是对于不能修改源代码的童鞋来说是不行的 所以一下解决方法诞生了 直接添加这三个按钮并和时间控件 laydate 有友好的
  • 【数字图像处理】图像形态学算法C语言实现(图像卷积,膨胀,腐蚀,开运算,闭运算,顶帽,黑帽,雕版,锐化)

    文章目录 一 图像卷积 1 图像卷积 2 数字信号处理中的卷积 3 数字图像处理中的卷积 二 图像卷积实现各种形态学运算 腐蚀 膨胀 形态学梯度 开运算 闭运算 顶帽 黑帽 雕版 锐化 li conv c main c 三 效果展示 原图