You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetson Nano下OpenCV Python3滤波后图像保存重复问题排查

问题描述

我需要将经过滤波处理的图像保存到对应文件夹,但遇到以下问题:第二次、第三次触发保存并尝试保存到新目录时,新文件夹中总是保存与初始图像高度相似的内容,而非触发操作时的实时图像。

推测程序可能在启动阶段就捕获了大量图像并缓存,这或许和Jetson Nano的内存限制有关。在if __name__ == "__main__"模块中,每个选项仅调用一次rec_image()函数,但实际却出现重复录制的情况。单独调用rec_image()函数时功能正常,但导入整个文件并运行main模块时问题复现。

相关代码如下(AI部分可忽略):

import cv2
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, concatenate, Input
from sklearn.model_selection import train_test_split
import numpy as np
from tensorflow.keras.utils import to_categorical
import os
from time import sleep


path = os.getcwd()
forward = "fd"
right = "rt"
left = "lt"
right_rotate = "rtr"
left_rotate = "ltr"

forward_folder = f"{os.path.join(path, forward)}"
right_folder = f"{os.path.join(path, right)}"
left_folder = f"{os.path.join(path, left)}"
rotate_right_folder = f"{os.path.join(path, right_rotate)}"
rotate_left_folder = f"{os.path.join(path, left_rotate)}"

fol2abbrev = {forward_folder : forward, right_folder : right, left_folder : left, rotate_right_folder : right_rotate, rotate_left_folder : left_rotate}

folders = [forward_folder, right_folder, left_folder, rotate_right_folder, rotate_left_folder]
abbrev = [forward, right, left, right_rotate, left_rotate]
recording_number = 1

for element in abbrev:
    try:
        os.mkdir(element)
    except Exception as e:
        #print(e)
        pass
cam = cv2.VideoCapture(0)
#Instantiate cv2 cam (TAKES LESS NOW)
width = int(cam.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT))

Images = np.empty((0, height, width))#set the image array to an empty one, with the shape of height width (To make the image shape)
labels = np.empty(0)
Lasers = np.empty((0, 5)) #Put 8 if 8 lasers in the end

def preprocess_image(image):
    # Grayscale
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # Blur the image
    blurred_image = cv2.GaussianBlur(image, (5, 5), 4)

    # Sharpen the image
    kernel = np.array([[-1, -1, -1],
                       [-1,  9, -1],
                       [-1, -1, -1]])
    sharpened_image = cv2.filter2D(blurred_image, -1, kernel)

    # Enhance contrast (optional)
    clahe = cv2.createCLAHE(clipLimit=16.0, tileGridSize=(16, 16))
    contrast_enhanced = clahe.apply(sharpened_image)

    return contrast_enhanced

def image_sort(path):
    images = []
    for element in os.listdir(path):
        if ".jpg" in element:
            images.append(element)
    return images

def text_sort(path):
    texts = []
    for element in os.listdir(path):
        if ".txt" in element:
            texts.append(element)
    return texts

def folder_value(folder):
    if folder == forward_folder:
        return 0
    elif folder == right_folder:
        return 1
    elif folder == left_folder:
        return 2
    elif folder == rotate_right_folder:
        return 3
    elif folder == rotate_left_folder:
        return 4
    else:
        raise "Problem with folder, the value given is not equal to a valid folder adress stated above!"

def rec_image(folder, times=1):
        ret, image = cam.read() #THE CAMERA SHOULD BE CONNECTED DIRECTLY TO JETSON NANO
        image = preprocess_image(image)
        print(f"IMAGE is being saved to {folder}")
        cv2.imwrite(f"{folder}/{len(image_sort(folder))}.jpg",image)

def rec_lasers(folder, times=1):
        data = [1,2,3,4,5] #GET DATA FROM LASERS WITH JETSON NANO
        file = open(f"{folder}/{len(text_sort(folder))}.txt", "w")
        file.write(str(data))
        file.close()

def read_data(folder):
    global Images, labels, Lasers
    for i in range(len(image_sort(folder))):
        if i < len(image_sort(folder))-1:
            image = cv2.imread(f"{folder}{i+1}.jpg", cv2.IMREAD_GRAYSCALE)
            Images = np.append(Images, [image], axis=0)
            labels = np.append(labels, folder_value(folder))
    for i in range(len(text_sort(folder))):
        if i < len(text_sort(folder))-1:
            data = open(folder+text_sort(folder)[i],"r")
            data = data.read().strip('][').split(', ')
            Lasers = np.append(Lasers, [data], axis=0) # Load the LASER DATA

def process_predictions(tensor): #Has to be a numpy tensor, because tensorflow const cannot append
    final_tensor = np.array([])
    for prediction in tensor:
        i = 1
        for choice in prediction:
            #print(choice)
            if round(float(choice)) == 1:
                final_tensor = np.concatenate((final_tensor, [i]))
                #print("IT SHOULD CONCAT 1!")
            else:
                i+=1
    return tf.constant(np.round(final_tensor))

def process_predictions_combined(predictions_image, predictions_laser):
    max_indices_image = np.argmax(predictions_image, axis=1)
    max_indices_laser = np.argmax(predictions_laser, axis=1)

    # Combine max indices for image and laser predictions
    combined_indices = np.column_stack((max_indices_image, max_indices_laser))

    return tf.constant(np.round(combined_indices))

def train():
    global Images, labels, Lasers

    for folder in folders:
        read_data(folder)

    Lasers = Lasers.reshape((Lasers.shape[0], Lasers.shape[1], 1))

    print(Images.shape)
    print(labels.shape)
    print(Lasers.shape)

    # Split the data
    train_images, test_images, train_labels, test_labels = train_test_split(Images, labels, test_size=0.1, random_state=21, stratify=labels)
    train_lasers, test_lasers, _, _ = train_test_split(Lasers, labels, test_size=0.1, random_state=21, stratify=labels)
    #print(f"LASERS : {train_lasers},{train_lasers.shape}")
    #Preprocess the data
    train_images = tf.expand_dims(train_images, axis=-1)
    test_images = tf.expand_dims(test_images, axis=-1)

    train_images = tf.cast(train_images, dtype=tf.int32)
    test_images = tf.cast(test_images, dtype=tf.int32)
    """
    train_lasers = tf.expand_dims(train_lasers, axis=-1)
    train_lasers = tf.expand_dims(train_lasers, axis=-1)"""

    train_lasers = tf.strings.to_number(train_lasers, out_type=tf.float64)
    test_lasers = tf.strings.to_number(test_lasers, out_type=tf.float64)

    train_labels = train_labels.astype(int)
    test_labels = test_labels.astype(int)
    laser_count = len(Lasers[0])

    print(f"LASERS : {train_lasers},{train_lasers.shape}")
    # CONV2D
    model1 = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=(height, width, 1), name="Image_Input"),
        tf.keras.layers.Conv2D(16, (3, 3), activation=tf.keras.activations.relu, name="Image_1_Conv2D"),
        tf.keras.layers.MaxPooling2D((2, 2), name="Image_2_Pooling2D"),
        tf.keras.layers.Conv2D(32, (3, 3), activation=tf.keras.activations.relu, name="Image_3_Conv2D"),
        tf.keras.layers.MaxPooling2D((2, 2), name="Image_4_Pooling2D"),
        tf.keras.layers.Conv2D(64, (3, 3), activation=tf.keras.activations.relu, name="Image_5_Conv2D"),
        tf.keras.layers.MaxPooling2D((2, 2),name="Image_6_Pooling2D"),
        tf.keras.layers.Flatten(name="Image_7_Flatten"),
        tf.keras.layers.Dropout(0.5,name="Image_8_Dropout"),
        tf.keras.layers.Dense(5, activation=tf.keras.activations.softmax)

    ])
    #CONV1D
    model2 = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=(laser_count, 1), name="Laser_Input"),
        tf.keras.layers.Conv1D(32, kernel_size=3, activation=tf.keras.activations.relu, name="Laser_Conv1D"),
        tf.keras.layers.Flatten(name="Laser_flatten"),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(5, activation=tf.keras.activations.softmax)
    ])
    #FC MODEL
    model3 = tf.keras.models.Sequential([
        tf.keras.layers.Input(shape=2, name="Combined_Input"),
        tf.keras.layers.Dense(32, activation=tf.keras.activations.relu, name="Combined_1_Dense"),
        tf.keras.layers.Dense(64, activation=tf.keras.activations.relu, name="Combined_2_Dense"),
        tf.keras.layers.Dropout(0.3, name="Combined_3_Dropout"),
        tf.keras.layers.Dense(5, activation=tf.keras.activations.softmax, name="Combined_OUTPUT")
    ])
    #Compile and train the models
    model1.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
                          loss=tf.keras.losses.sparse_categorical_crossentropy, #Because it is category, mse is for numbers
                          metrics=["accuracy"])

    model2.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.003),
                          loss=tf.keras.losses.sparse_categorical_crossentropy, #Because it is category, mse is for numbers
                          metrics=["accuracy"])

    model3.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.005),
                          loss=tf.keras.losses.sparse_categorical_crossentropy, #Because it is category, mse is for numbers
                          metrics=["accuracy"])
    #print(train_labels)
    model1.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
    """print("Train lasers shape:", train_lasers.shape)
    print("Test lasers shape:", test_lasers.shape)
    """

    model2.fit(train_lasers, train_labels, epochs=10, validation_data=(test_lasers, test_labels))

    predictions_model1 = model1.predict(train_images)
    predictions_model2 = model2.predict(train_lasers)

    # Concatenate predictions along the axis corresponding to models (axis=1)
    """print(len(train_images)+len(train_lasers))
    print("LENGTH of predictions",len(predictions))
    print("LENGTH of predictions[0]", len(predictions[0]))
    print(np.array(predictions).shape)
    print(predictions)"""
    predictions = process_predictions_combined(predictions_model1, predictions_model2)
    print(predictions)
    print(len(predictions))
    #predictions = process_predictions(predictions)
    #predictions = predictions #- 1
    print(f"Predictions : {predictions.shape}")
    print(f"Labels : {train_labels.shape}")

    model3.fit(predictions-1, train_labels, epochs=25)

    model1.save("models/2DCNN")
    model2.save("models/1DCNN")
    model3.save("models/FCNN")
    return model1, model2, model3


def predict(images, lasers):
    sleep(1)

    predictions_model1 = model1.predict(images)
    predictions_model2 = model2.predict(lasers)
    combined = process_predictions_combined(predictions_model1, predictions_model2)
    combined = combined - 1
    print(combined, combined.shape)

    pred3 = model3.predict(combined)
    print(pred3)
    print(pred3.argmax())
    return pred3.argmax()

if __name__ == "__main__":
        if cam.isOpened():
                while True:
                        main = input("1(fd), 2(rt), 3(lt), 4(rtr), 5(ltr), 6(Train), 7(predict)")
                        #Instead of input, get values from recv
                        #Channel 1 to fwd
                        #Channel 2 to rt and lt (depends on the number)
                        #Channel 3 constant (set drone to hover / constant throttle)
                        #Channel 4 to rtr and ltr (depends on number)

                        if main == "1":
                            rec_image(forward_folder, recording_number)
                            rec_lasers(forward_folder, recording_number)
                        elif main == "2":
                            rec_image(right_folder, recording_number)
                            rec_lasers(right_folder, recording_number)
                        elif main == "3":
                            rec_image(left_folder, recording_number)
                            rec_lasers(left_folder, recording_number)
                        elif main == "4":
                            rec_image(rotate_right_folder, recording_number)
                            rec_lasers(rotate_right_folder, recording_number)
                        elif main == "5":
                            rec_image(rotate_left_folder, recording_number)
                            rec_lasers(rotate_left_folder, recording_number)
                        elif main == "6":
                            model1, model2, model3 = train()
                        elif main == "7":
                            predict()
原因分析

问题核心在于Jetson Nano的摄像头帧缓存机制:

  • OpenCV的VideoCapture对象会持续从摄像头抓取帧并存储在缓冲区中,当程序长时间未调用cam.read()时,缓冲区会积累大量旧帧。
  • 触发保存操作时调用cam.read(),读取的是缓冲区中最早的旧帧,而非当前实时画面,导致多次保存的图像高度相似。
解决方案

有两种可行的修复方式:

方式一:保存前清空缓冲区

修改rec_image函数,在读取目标帧前先读取并丢弃若干帧,确保获取最新的实时图像:

def rec_image(folder, times=1):
    # 读取并丢弃3帧清空缓冲区(数量可根据实际情况调整)
    for _ in range(3):
        cam.read()
    # 读取最新帧
    ret, image = cam.read()
    if not ret:
        print("无法读取摄像头帧")
        return
    image = preprocess_image(image)
    print(f"IMAGE is being saved to {folder}")
    cv2.imwrite(f"{folder}/{len(image_sort(folder))}.jpg", image)

方式二:主循环中持续读取帧

在主循环里持续读取帧,即使不保存也保持缓冲区清空,这样需要保存时读取的就是最新帧:

if __name__ == "__main__":
        if cam.isOpened():
                while True:
                        # 持续读取帧,清空缓冲区
                        ret, _ = cam.read()
                        if not ret:
                            print("摄像头读取失败")
                            break
                        main = input("1(fd), 2(rt), 3(lt), 4(rtr), 5(ltr), 6(Train), 7(predict)")
                        
                        if main == "1":
                            rec_image(forward_folder, recording_number)
                            rec_lasers(forward_folder, recording_number)
                        elif main == "2":
                            rec_image(right_folder, recording_number)
                            rec_lasers(right_folder, recording_number)
                        elif main == "3":
                            rec_image(left_folder, recording_number)
                            rec_lasers(left_folder, recording_number)
                        elif main == "4":
                            rec_image(rotate_right_folder, recording_number)
                            rec_lasers(rotate_right_folder, recording_number)
                        elif main == "5":
                            rec_image(rotate_left_folder, recording_number)
                            rec_lasers(rotate_left_folder, recording_number)
                        elif main == "6":
                            model1, model2, model3 =
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:02:49