欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python神經(jīng)網(wǎng)絡Keras?GhostNet模型的實現(xiàn)

 更新時間:2022年05月07日 16:15:21   作者:Bubbliiiing  
這篇文章主要為大家介紹了python神經(jīng)網(wǎng)絡Keras?GhostNet模型的復現(xiàn)詳解,

什么是GhostNet模型

GhostNet是華為諾亞方舟實驗室提出來的一個非常有趣的網(wǎng)絡,我們一起來學習一下。

2020年,華為新出了一個輕量級網(wǎng)絡,命名為GhostNet。

在優(yōu)秀CNN模型中,特征圖存在冗余是非常重要的。如圖所示,這個是對ResNet-50第一個殘差塊特征圖進行可視化的結(jié)果,當我們給一個神經(jīng)網(wǎng)絡輸入一張圖片時,我們可以獲得特別多的特征圖。

利用小扳手連接起來的兩幅特征圖,它們的相似性就特別高,這個就是神經(jīng)網(wǎng)絡中存在的特征圖冗雜的情況。

作者將相似的特征圖認為是彼此的Ghost,所以這個網(wǎng)絡就叫做GhostNet(誤)。

在GhostNet這篇論文里面,作者認為可以使用一些計算量更低(Cheap Operations)的操作去生成這些冗余的特征圖,這樣就可以在保證良好檢測效果的情況下,減少模型的參數(shù)量與提高模型的執(zhí)行速度。

源碼下載

GhostNet模型的實現(xiàn)思路

1、Ghost Module

通過上述的介紹,我們了解到了,GhostNet的核心思想就是使用一些計算量更低(Cheap Operations)的操作去生成這些冗余的特征圖。

在論文中,作者設計了一個名為Ghost Module的模塊,他的功能是代替普通卷積。

Ghost Module將普通卷積分為兩部分,首先進行一個普通的1x1卷積,這是一個少量卷積,比如正常使用32通道的卷積,這里就用16通道的卷積,這個1x1卷積的作用類似于特征整合,生成輸入特征層的特征濃縮。

然后我們再進行深度可分離卷積,這個深度可分離卷積是逐層卷積,它也就是我們上面提到的Cheap Operations。它利用上一步獲得的特征濃縮生成Ghost特征圖。

因此,如果我們從整體上去看這個Ghost Module,它其實就是兩步簡單思想的匯總:

1、利用1x1卷積獲得輸入特征的必要特征濃縮。

2、利用深度可分離卷積獲得特征濃縮的相似特征圖(Ghost)。

Ghost Module的實現(xiàn)代碼如下:

def _ghost_module(inputs, exp, kernel, dw_kernel, ratio, strides=1,
                    padding='same',use_bias=False, relu=True):
    output_channels = math.ceil(exp * 1.0 / ratio)
    x = Conv2D(output_channels, kernel, strides=strides, padding=padding, use_bias=use_bias)(inputs)
    x = BatchNormalization()(x)
    if relu:
        x = Activation('relu')(x)
    dw = DepthwiseConv2D(dw_kernel, strides, padding=padding, depth_multiplier=ratio-1, use_bias=use_bias)(x)
    dw = BatchNormalization()(dw)
    if relu:
        dw = Activation('relu')(dw)
    x = Concatenate(axis=-1)([x,dw])
    x = Lambda(slices, arguments={'n':exp})(x)
    return x

2、Ghost Bottlenecks

Ghost Bottlenecks是由Ghost Module組成的瓶頸結(jié)構(gòu),就像這樣。

其實本質(zhì)上就是用Ghost Module,來代替瓶頸結(jié)構(gòu)里面的普通卷積。

Ghost Bottlenecks可以分為兩個部分,分別是主干部分和殘差邊部分,包含Ghost Module的,我們稱它為主干部分。

Ghost Bottlenecks有兩個種類,如下圖所示,當我們需要對特征層的寬高進行壓縮的時候,我們會設置這個Ghost Bottlenecks的Stride=2,即步長為2。

此時我們會Bottlenecks里面多添加一些卷積層,在主干部分里,我們會在兩個Ghost Module中添加一個步長為2x2的深度可分離卷積進行特征層的寬高壓縮。在殘差邊部分,我們也會添加上一個步長為2x2的深度可分離卷積和1x1的普通卷積。

Ghost Bottlenecks的實現(xiàn)代碼如下:

def _ghost_bottleneck(inputs, output_channel, hidden_channel, kernel, ghost_kernel, strides, ratio, squeeze):
    input_shape = K.int_shape(inputs)       # 獲取輸入張量的尺寸
    x = _ghost_module(inputs, hidden_channel, [1,1], ghost_kernel, ratio)
    if strides > 1:
        x = DepthwiseConv2D(kernel, strides, padding='same', depth_multiplier=1, use_bias=False)(x)
        x = BatchNormalization()(x)
    if squeeze:
        x = _squeeze(x, hidden_channel, 4)
    x = _ghost_module(x, output_channel, [1,1], ghost_kernel, ratio, relu=False)
    if strides == 1 and input_shape[-1] == output_channel:
        res = inputs
    else:
        res = DepthwiseConv2D(kernel, strides=strides, padding='same', depth_multiplier=1, use_bias=False)(inputs)
        res = BatchNormalization()(res)
        res = Conv2D(output_channel, (1, 1), padding='same', strides=(1, 1), use_bias=False)(res)
        res = BatchNormalization()(res)
    x = Add()([res, x])
    return x

3、Ghostnet的構(gòu)建

整個Ghostnet的構(gòu)建方式如列表所示:

可以看到,整個Ghostnet都是由Ghost Bottlenecks進行組成的。

當一張圖片輸入到Ghostnet當中時,我們首先進行一個16通道的普通1x1卷積塊(卷積+標準化+激活函數(shù))。

之后我們就開始Ghost Bottlenecks的堆疊了,利用Ghost Bottlenecks,我們最終獲得了一個7x7x160的特征層(當輸入是224x224x3的時候)。

然后我們會利用一個1x1的卷積塊進行通道數(shù)的調(diào)整,此時我們可以獲得一個7x7x960的特征層。

之后我們進行一次全局平均池化,然后再利用一個1x1的卷積塊進行通道數(shù)的調(diào)整,獲得一個1x1x1280的特征層。

然后平鋪后進行全連接就可以進行分類了。

GhostNet的代碼構(gòu)建

1、模型代碼的構(gòu)建

GhostNet的實現(xiàn)代碼如下,該代碼是Ghostnet在YoloV4上的應用,可以參考一下:

import math
import warnings
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.applications.imagenet_utils import decode_predictions
from keras.initializers import random_normal
from keras.layers import (Activation, Add, BatchNormalization, Concatenate,
                          Conv2D, DepthwiseConv2D, GlobalAveragePooling2D, 
                          Lambda, Multiply, Reshape)
def slices(dw, n):
    return dw[:,:,:,:n]
def _make_divisible(v, divisor, min_value=None):
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v
def _squeeze(inputs, hidden_channel, ratio, block_id, sub_block_id):
    x = GlobalAveragePooling2D()(inputs)
    x = Reshape((1,1,-1))(x)
    x = Conv2D(_make_divisible(hidden_channel/ratio, 4), (1,1), strides=(1,1), padding='same', kernel_initializer=random_normal(stddev=0.02),
            name="blocks."+str(block_id)+"."+str(sub_block_id)+".se.conv_reduce")(x)
    x = Activation('relu')(x)
    x = Conv2D(hidden_channel, (1,1),strides=(1,1), padding='same', kernel_initializer=random_normal(stddev=0.02),
            name="blocks."+str(block_id)+"."+str(sub_block_id)+".se.conv_expand")(x)
    x = Activation('hard_sigmoid')(x)
    x = Multiply()([inputs, x])    # inputs和x逐元素相乘
    return x
def _ghost_module(inputs, exp, ratio, block_id, sub_block_id, part, kernel_size=1, dw_size=3, stride=1, relu=True):
    output_channels = math.ceil(exp * 1.0 / ratio)
    x = Conv2D(output_channels, kernel_size, strides=stride, padding="same", use_bias=False, kernel_initializer=random_normal(stddev=0.02),
            name="blocks."+str(block_id)+"."+str(sub_block_id)+".ghost"+str(part)+".primary_conv.0")(inputs)
    x = BatchNormalization(name="blocks."+str(block_id)+"."+str(sub_block_id)+".ghost"+str(part)+".primary_conv.1")(x)
    if relu:
        x = Activation('relu')(x)
    dw = DepthwiseConv2D(dw_size, 1, padding="same", depth_multiplier=ratio-1, use_bias=False, depthwise_initializer=random_normal(stddev=0.02), 
            name="blocks."+str(block_id)+"."+str(sub_block_id)+".ghost"+str(part)+".cheap_operation.0")(x)
    dw = BatchNormalization(name="blocks."+str(block_id)+"."+str(sub_block_id)+".ghost"+str(part)+".cheap_operation.1")(dw)
    if relu:
        dw = Activation('relu')(dw)
    x = Concatenate(axis=-1)([x,dw])
    x = Lambda(slices, arguments={'n':exp})(x)
    return x
def _ghost_bottleneck(inputs, output_channel, hidden_channel, kernel, strides, ratio, squeeze, block_id, sub_block_id):
    input_shape = K.int_shape(inputs)
    x = _ghost_module(inputs, hidden_channel, ratio, block_id, sub_block_id, 1)
    if strides > 1:
        x = DepthwiseConv2D(kernel, strides, padding='same', depth_multiplier=1, use_bias=False, depthwise_initializer=random_normal(stddev=0.02),
                name="blocks."+str(block_id)+"."+str(sub_block_id)+".conv_dw")(x)
        x = BatchNormalization(name="blocks."+str(block_id)+"."+str(sub_block_id)+".bn_dw")(x)
    if squeeze:
        x = _squeeze(x, hidden_channel, 4, block_id, sub_block_id)
    x = _ghost_module(x, output_channel, ratio, block_id, sub_block_id, 2, relu=False)
    if strides == 1 and input_shape[-1] == output_channel:
        res = inputs
    else:
        res = DepthwiseConv2D(kernel, strides=strides, padding='same', depth_multiplier=1, use_bias=False, depthwise_initializer=random_normal(stddev=0.02),
                name="blocks."+str(block_id)+"."+str(sub_block_id)+".shortcut.0")(inputs)
        res = BatchNormalization(name="blocks."+str(block_id)+"."+str(sub_block_id)+".shortcut.1")(res)
        res = Conv2D(output_channel, (1, 1), padding='same', strides=(1, 1), use_bias=False, kernel_initializer=random_normal(stddev=0.02),
                name="blocks."+str(block_id)+"."+str(sub_block_id)+".shortcut.2")(res)
        res = BatchNormalization(name="blocks."+str(block_id)+"."+str(sub_block_id)+".shortcut.3")(res)
    x = Add()([res, x])
    return x
def Ghostnet(inputs):
    x = Conv2D(16, (3, 3), padding="same", strides=(2, 2), use_bias=False, kernel_initializer=random_normal(stddev=0.02), name="conv_stem")(inputs)
    x = BatchNormalization(name="bn1")(x)
    x = Activation('relu')(x)
    x = _ghost_bottleneck(x, 16, 16, (3, 3), strides=1, ratio=2, squeeze=False, block_id=0, sub_block_id=0)
    x = _ghost_bottleneck(x, 24, 48, (3, 3), strides=2, ratio=2, squeeze=False, block_id=1, sub_block_id=0)
    x = _ghost_bottleneck(x, 24, 72, (3, 3), strides=1, ratio=2, squeeze=False, block_id=2, sub_block_id=0)
    x = _ghost_bottleneck(x, 40, 72, (5, 5), strides=2, ratio=2, squeeze=True, block_id=3, sub_block_id=0)
    x = _ghost_bottleneck(x, 40, 120, (5, 5), strides=1, ratio=2, squeeze=True, block_id=4, sub_block_id=0)
    feat1 = x
    x = _ghost_bottleneck(x, 80, 240, (3, 3), strides=2, ratio=2, squeeze=False, block_id=5, sub_block_id=0)
    x = _ghost_bottleneck(x, 80, 200, (3, 3), strides=1, ratio=2, squeeze=False, block_id=6, sub_block_id=0)
    x = _ghost_bottleneck(x, 80, 184, (3, 3), strides=1, ratio=2, squeeze=False, block_id=6, sub_block_id=1)
    x = _ghost_bottleneck(x, 80, 184, (3, 3), strides=1, ratio=2, squeeze=False, block_id=6, sub_block_id=2)
    x = _ghost_bottleneck(x, 112, 480, (3, 3), strides=1, ratio=2, squeeze=True, block_id=6, sub_block_id=3)
    x = _ghost_bottleneck(x, 112, 672, (3, 3), strides=1, ratio=2, squeeze=True, block_id=6, sub_block_id=4)
    feat2 = x
    x = _ghost_bottleneck(x, 160, 672, (5, 5), strides=2, ratio=2, squeeze=True, block_id=7, sub_block_id=0)
    x = _ghost_bottleneck(x, 160, 960, (5, 5), strides=1, ratio=2, squeeze=False, block_id=8, sub_block_id=0)
    x = _ghost_bottleneck(x, 160, 960, (5, 5), strides=1, ratio=2, squeeze=True, block_id=8, sub_block_id=1)
    x = _ghost_bottleneck(x, 160, 960, (5, 5), strides=1, ratio=2, squeeze=False, block_id=8, sub_block_id=2)
    x = _ghost_bottleneck(x, 160, 960, (5, 5), strides=1, ratio=2, squeeze=True, block_id=8, sub_block_id=3)
    feat3 = x
    return feat1,feat2,feat3

2、Yolov4上的應用

作為一個輕量級網(wǎng)絡,我把Ghostnet和Mobilenet放在一起,作為Yolov4的主干網(wǎng)絡進行特征提取。

對于yolov4來講,我們需要利用主干特征提取網(wǎng)絡獲得的三個有效特征進行加強特征金字塔的構(gòu)建。

我們通過上述代碼可以取出三個有效特征層,我們可以利用這三個有效特征層替換原來yolov4主干網(wǎng)絡CSPdarknet53的有效特征層。

為了進一步減少參數(shù)量,我們可以使用深度可分離卷積代替yoloV3中用到的普通卷積。

最終Ghostnet-Yolov4的構(gòu)建代碼如下:

from functools import wraps
from keras import backend as K
from keras.initializers import random_normal
from keras.layers import (Activation, BatchNormalization, Concatenate, Conv2D,
                          DepthwiseConv2D, Input, Lambda, MaxPooling2D,
                          UpSampling2D)
from keras.layers.normalization import BatchNormalization
from keras.models import Model
from keras.regularizers import l2
from utils.utils import compose
from nets.ghostnet import Ghostnet
from nets.mobilenet_v1 import MobileNetV1
from nets.mobilenet_v2 import MobileNetV2
from nets.mobilenet_v3 import MobileNetV3
from nets.yolo_training import yolo_loss
def relu6(x):
    return K.relu(x, max_value=6)
#------------------------------------------------------#
#   單次卷積DarknetConv2D
#   如果步長為2則自己設定padding方式。
#------------------------------------------------------#
@wraps(Conv2D)
def DarknetConv2D(*args, **kwargs):
    darknet_conv_kwargs = {'kernel_initializer' : random_normal(stddev=0.02), 'kernel_regularizer': l2(5e-4)}
    darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'
    darknet_conv_kwargs.update(kwargs)
    return Conv2D(*args, **darknet_conv_kwargs)
#---------------------------------------------------#
#   卷積塊 -> 卷積 + 標準化 + 激活函數(shù)
#   DarknetConv2D + BatchNormalization + Relu6
#---------------------------------------------------#
def DarknetConv2D_BN_Leaky(*args, **kwargs):
    no_bias_kwargs = {'use_bias': False}
    no_bias_kwargs.update(kwargs)
    return compose( 
        DarknetConv2D(*args, **no_bias_kwargs),
        BatchNormalization(),
        Activation(relu6))
#---------------------------------------------------#
#   深度可分離卷積塊
#   DepthwiseConv2D + BatchNormalization + Relu6
#---------------------------------------------------#
def _depthwise_conv_block(inputs, pointwise_conv_filters, alpha = 1,
                          depth_multiplier=1, strides=(1, 1)):
    pointwise_conv_filters = int(pointwise_conv_filters * alpha)
    x = DepthwiseConv2D((3, 3), depthwise_initializer=random_normal(stddev=0.02),
                        padding='same',
                        depth_multiplier=depth_multiplier,
                        strides=strides,
                        use_bias=False)(inputs)
    x = BatchNormalization()(x)
    x = Activation(relu6)(x)
    x = DarknetConv2D(pointwise_conv_filters, (1, 1), 
                    padding='same',
                    use_bias=False,
                    strides=(1, 1))(x)
    x = BatchNormalization()(x)
    return Activation(relu6)(x)
#---------------------------------------------------#
#   進行五次卷積
#---------------------------------------------------#
def make_five_convs(x, num_filters):
    # 五次卷積
    x = DarknetConv2D_BN_Leaky(num_filters, (1,1))(x)
    x = _depthwise_conv_block(x, num_filters*2,alpha=1)
    x = DarknetConv2D_BN_Leaky(num_filters, (1,1))(x)
    x = _depthwise_conv_block(x, num_filters*2,alpha=1)
    x = DarknetConv2D_BN_Leaky(num_filters, (1,1))(x)
    return x
#---------------------------------------------------#
#   Panet網(wǎng)絡的構(gòu)建,并且獲得預測結(jié)果
#---------------------------------------------------#
def yolo_body(input_shape, anchors_mask, num_classes, backbone="mobilenetv1", alpha=1):
    inputs = Input(input_shape)
    #---------------------------------------------------#   
    #   生成mobilnet的主干模型,獲得三個有效特征層。
    #---------------------------------------------------#
    if backbone=="mobilenetv1":
        #---------------------------------------------------#   
        #   52,52,256;26,26,512;13,13,1024
        #---------------------------------------------------#
        feat1,feat2,feat3 = MobileNetV1(inputs, alpha=alpha)
    elif backbone=="mobilenetv2":
        #---------------------------------------------------#   
        #   52,52,32;26,26,92;13,13,320
        #---------------------------------------------------#
        feat1,feat2,feat3 = MobileNetV2(inputs, alpha=alpha)
    elif backbone=="mobilenetv3":
        #---------------------------------------------------#   
        #   52,52,40;26,26,112;13,13,160
        #---------------------------------------------------#
        feat1,feat2,feat3 = MobileNetV3(inputs, alpha=alpha)
    elif backbone=="ghostnet":
        #---------------------------------------------------#   
        #   52,52,40;26,26,112;13,13,160
        #---------------------------------------------------#
        feat1,feat2,feat3 = Ghostnet(inputs)
    else:
        raise ValueError('Unsupported backbone - `{}`, Use mobilenetv1, mobilenetv2, mobilenetv3, ghostnet.'.format(backbone))
    P5 = DarknetConv2D_BN_Leaky(int(512* alpha), (1,1))(feat3)
    P5 = _depthwise_conv_block(P5, int(1024* alpha))
    P5 = DarknetConv2D_BN_Leaky(int(512* alpha), (1,1))(P5)
    maxpool1 = MaxPooling2D(pool_size=(13,13), strides=(1,1), padding='same')(P5)
    maxpool2 = MaxPooling2D(pool_size=(9,9), strides=(1,1), padding='same')(P5)
    maxpool3 = MaxPooling2D(pool_size=(5,5), strides=(1,1), padding='same')(P5)
    P5 = Concatenate()([maxpool1, maxpool2, maxpool3, P5])
    P5 = DarknetConv2D_BN_Leaky(int(512* alpha), (1,1))(P5)
    P5 = _depthwise_conv_block(P5, int(1024* alpha))
    P5 = DarknetConv2D_BN_Leaky(int(512* alpha), (1,1))(P5)
    P5_upsample = compose(DarknetConv2D_BN_Leaky(int(256* alpha), (1,1)), UpSampling2D(2))(P5)
    P4 = DarknetConv2D_BN_Leaky(int(256* alpha), (1,1))(feat2)
    P4 = Concatenate()([P4, P5_upsample])
    P4 = make_five_convs(P4,int(256* alpha))
    P4_upsample = compose(DarknetConv2D_BN_Leaky(int(128* alpha), (1,1)), UpSampling2D(2))(P4)
    P3 = DarknetConv2D_BN_Leaky(int(128* alpha), (1,1))(feat1)
    P3 = Concatenate()([P3, P4_upsample])
    P3 = make_five_convs(P3,int(128* alpha))
    #---------------------------------------------------#
    #   第三個特征層
    #   y3=(batch_size,52,52,3,85)
    #---------------------------------------------------#
    P3_output = _depthwise_conv_block(P3, int(256* alpha))
    P3_output = DarknetConv2D(len(anchors_mask[0])*(num_classes+5), (1,1))(P3_output)
    P3_downsample = _depthwise_conv_block(P3, int(256* alpha), strides=(2,2))
    P4 = Concatenate()([P3_downsample, P4])
    P4 = make_five_convs(P4,int(256* alpha))
    #---------------------------------------------------#
    #   第二個特征層
    #   y2=(batch_size,26,26,3,85)
    #---------------------------------------------------#
    P4_output = _depthwise_conv_block(P4, int(512* alpha))
    P4_output = DarknetConv2D(len(anchors_mask[1])*(num_classes+5), (1,1))(P4_output)
    P4_downsample = _depthwise_conv_block(P4, int(512* alpha), strides=(2,2))
    P5 = Concatenate()([P4_downsample, P5])
    P5 = make_five_convs(P5,int(512* alpha))
    #---------------------------------------------------#
    #   第一個特征層
    #   y1=(batch_size,13,13,3,85)
    #---------------------------------------------------#
    P5_output = _depthwise_conv_block(P5, int(1024* alpha))
    P5_output = DarknetConv2D(len(anchors_mask[2])*(num_classes+5), (1,1))(P5_output)
    return Model(inputs, [P5_output, P4_output, P3_output])

以上就是python神經(jīng)網(wǎng)絡Keras GhostNet模型的復現(xiàn)詳解的詳細內(nèi)容,更多關(guān)于Keras GhostNet模型復現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python 實現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例

    python 實現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例

    今天小編就為大家分享一篇python 實現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • python語言中with as的用法使用詳解

    python語言中with as的用法使用詳解

    本篇文章主要介紹了python語言中with as的用法使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Python 函數(shù)用法簡單示例【定義、參數(shù)、返回值、函數(shù)嵌套】

    Python 函數(shù)用法簡單示例【定義、參數(shù)、返回值、函數(shù)嵌套】

    這篇文章主要介紹了Python 函數(shù)用法,結(jié)合實例形式分析了Python函數(shù)定義、參數(shù)、返回值及函數(shù)嵌套相關(guān)使用技巧,需要的朋友可以參考下
    2019-09-09
  • Django 創(chuàng)建新App及其常用命令的實現(xiàn)方法

    Django 創(chuàng)建新App及其常用命令的實現(xiàn)方法

    這篇文章主要介紹了Django 創(chuàng)建新App及其常用命令的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • Python?OpenCV實現(xiàn)圖像增強操作詳解

    Python?OpenCV實現(xiàn)圖像增強操作詳解

    由于很多不確定因素,導致圖像采集的光環(huán)境極其復雜;為了提高目標檢測模型的泛化能力,本文將使用python中的opencv模塊實現(xiàn)常見的圖像增強方法,感興趣的可以了解一下
    2022-10-10
  • Python OpenCV實現(xiàn)裁剪并保存圖片

    Python OpenCV實現(xiàn)裁剪并保存圖片

    這篇文章主要為大家詳細介紹了Python OpenCV實現(xiàn)裁剪并保存圖片,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • django的安裝和創(chuàng)建應用過程詳解

    django的安裝和創(chuàng)建應用過程詳解

    這篇文章主要介紹了django的安裝和創(chuàng)建應用,本文通過圖文并茂的形式給大家介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • Python queue模塊攻略全解

    Python queue模塊攻略全解

    這篇文章主要為大家介紹了Python queue模塊攻略全解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • python鏈接Oracle數(shù)據(jù)庫的方法

    python鏈接Oracle數(shù)據(jù)庫的方法

    這篇文章主要介紹了python鏈接Oracle數(shù)據(jù)庫的方法,實例分析了Python使用cx_Oracle模塊操作Oracle數(shù)據(jù)庫的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • Webots下載安裝?+?Pycharm聯(lián)調(diào)使用教程

    Webots下載安裝?+?Pycharm聯(lián)調(diào)使用教程

    Webots是一個開源的三維移動機器人模擬器,它最初是作為研究移動機器人中各種控制算法的研究工具開發(fā)的,自2018年12月起,Webots作為開源軟件發(fā)布,并獲得Apache 2.0許可證,這篇文章主要介紹了Webots下載安裝?+?Pycharm聯(lián)調(diào)?,需要的朋友可以參考下
    2023-02-02

最新評論