画像データのクリーニング

序文

データは、深層学習アルゴリズム モデルの有効性にとって非常に重要です。通常、収集された大量のデータにラベルを付ける前に、いくつかのデータ クリーニング作業を行う必要があります。大量のデータの場合、手動による直接クリーニングの速度は非常に遅くなります。そのため、最初にバッチ データを自動的にクリーニングし、その後手動で確認してクリーニングする自動クリーニング ツールを開発すると、効率が大幅に向上します。

ツール機能

収集された要件に従って、このツールは主に次の機能を実現します。

  • 統計データ情報 (占有スペースの合計、数量、破損した写真の数);
  • 破損した画像を削除し、
  • ぼやけた写真を削除し、
  • 類似した画像を削除し、
  • 自動車の色の分類、
  • 日内分類

統計情報

# 获取数据集存储大小、图片数量、破损图片数量
def get_data_info(dir_path):
    size = 0
    number = 0
    bad_number = 0
    for root, dirs, files in os.walk(dir_path):
        img_files = [file_name for file_name in files if is_image(file_name)]
        files_size = sum([os.path.getsize(os.path.join(root, file_name)) for file_name in img_files])
        files_number = len(img_files)
        size += files_size
        number += files_number
        for file in img_files:
            try:
                img = Image.open(os.path.join(root, file))
                img.load()
            except OSError:
                bad_number += 1
    return size / 1024 / 1024, number, bad_number

破損した画像を削除する

# 去除已损坏图片
def filter_bad(dir_path):
    filter_dir = os.path.join(os.path.dirname(dir_path), 'filter_bad')
    if not os.path.exists(filter_dir):
        os.mkdir(filter_dir)
    filter_number = 0
    for root, dirs, files in os.walk(dir_path):
        img_files = [file_name for file_name in files if is_image(file_name)]
        for file in img_files:
            file_path = os.path.join(root, file)
            try:
                Image.open(file_path).load()
            except OSError:
                shutil.move(file_path, filter_dir)
                filter_number += 1
    return filter_number

ぼやけた写真を削除する

まず、画像のシャープネスを判断する必要があり、opencv が提供するラプラシアン オペレーター インターフェイスを使用してシャープネスの値を取得します。値が小さいほどシャープネスは低くなり、ぼやけます (通常は 100-ビットカットオフ値)。

# 去除模糊图片
def filter_blurred(dir_path):
    filter_dir = os.path.join(os.path.dirname(dir_path), 'filter_blurred')
    if not os.path.exists(filter_dir):
        os.mkdir(filter_dir)
    filter_number = 0
    for root, dirs, files in os.walk(dir_path):
        img_files = [file_name for file_name in files if is_image(file_name)]
        for file in img_files:
            file_path = os.path.join(root, file)
            # img = cv2.imread(file_path)
            img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
            image_var = cv2.Laplacian(img, cv2.CV_64F).var()
            if image_var < 100:
                shutil.move(file_path, filter_dir)
                filter_number += 1
    return filter_number

画像のぼやけを検出するには多くの方法があります。https://www.cnblogs.com/greentomlee/p/9379471.html を参照してください。

類似した画像を削除する

ビデオフレームをサンプリングして得られる画像データの中には、連続する画像の類似性が非常に高いものがあるため、類似性の高い画像データを除外する必要がある。
まず、2 つの画像の類似度を計算する必要がありますが、類似度を計算するには、通常次のような方法があります。

  • ヒストグラムを通じて画像の類似性を計算します。
  • ハッシュ値、ハミング距離計算を通じて;
  • 画像のコサイン距離によって計算されます。
  • 画像の構造メトリクスによって計算されます。

4 つの方法の結果は異なる場合があります。
参考: https://blog.csdn.net/weixin_35132022/article/details/112514520
以下は、Python opencv を使用して、ヒストグラムを通じて画像の類似性を計算する方法です。類似した画像を削除するプロセスでは、各画像とその後の 4 枚の画像の間の類似性を調べます (ここでの比較後のいくつかの画像は、実際のニーズに応じて調整できます)。類似性がしきい値を超えた場合、後続の画像は削除されます。

# 计算两张图片的相似度
def calc_similarity(img1_path, img2_path):
    img1 = cv2.imdecode(np.fromfile(img1_path, dtype=np.uint8), -1)
    H1 = cv2.calcHist([img1], [1], None, [256], [0, 256])  # 计算图直方图
    H1 = cv2.normalize(H1, H1, 0, 1, cv2.NORM_MINMAX, -1)  # 对图片进行归一化处理
    img2 = cv2.imdecode(np.fromfile(img2_path, dtype=np.uint8), -1)
    H2 = cv2.calcHist([img2], [1], None, [256], [0, 256])  # 计算图直方图
    H2 = cv2.normalize(H2, H2, 0, 1, cv2.NORM_MINMAX, -1)  # 对图片进行归一化处理
    similarity1 = cv2.compareHist(H1, H2, 0)  # 相似度比较
    print('similarity:', similarity1)
    if similarity1 > 0.98:  # 0.98是阈值,可根据需求调整
        return True
    else:
        return False

# 去除相似度高的图片
def filter_similar(dir_path):
    filter_dir = os.path.join(os.path.dirname(dir_path), 'filter_similar')
    if not os.path.exists(filter_dir):
        os.mkdir(filter_dir)
    filter_number = 0
    for root, dirs, files in os.walk(dir_path):
        img_files = [file_name for file_name in files if is_image(file_name)]
        filter_list = []
        for index in range(len(img_files))[:-4]:
            if img_files[index] in filter_list:
                continue
            for idx in range(len(img_files))[(index+1):(index+5)]:
                img1_path = os.path.join(root, img_files[index])
                img2_path = os.path.join(root, img_files[idx])
                if calc_similarity(img1_path, img2_path):
                    filter_list.append(img_files[idx])
                    filter_number += 1
        for item in filter_list:
            src_path = os.path.join(root, item)
            shutil.move(src_path, filter_dir)
    return filter_number

自動車の色の分類

方法 1: 従来のアルゴリズム (満足のいく結果が得られない)

処理には opencv ライブラリ関数を使用します。

1. 画像の色を hsv に変換します。
2. cv2.inRange() 関数を使用して背景色をフィルターします。
3. フィルターされた色を 2 値化します。
4. 形態学的収縮と拡張を実行します。 cv2.dilate()
5. 統計領域白い部分
参考:https://www.jb51.net/article/172797.htm

# 定义HSV颜色字典
def get_color_list():
    dict = collections.defaultdict(list)
    # 黑色
    lower_black = np.array([0, 0, 0])
    upper_black = np.array([180, 255, 46])
    color_list = []
    color_list.append(lower_black)
    color_list.append(upper_black)
    dict['black'] = color_list

    # 灰色
    # lower_gray = np.array([0, 0, 46])
    # upper_gray = np.array([180, 43, 220])
    # color_list = []
    # color_list.append(lower_gray)
    # color_list.append(upper_gray)
    # dict['gray'] = color_list

    # 白色
    lower_white = np.array([0, 0, 221])
    upper_white = np.array([180, 30, 255])
    color_list = []
    color_list.append(lower_white)
    color_list.append(upper_white)
    dict['white'] = color_list

    # 红色1
    lower_red = np.array([156, 43, 46])
    upper_red = np.array([180, 255, 255])
    color_list = []
    color_list.append(lower_red)
    color_list.append(upper_red)
    dict['red'] = color_list

    # 红色2
    lower_red = np.array([0, 43, 46])
    upper_red = np.array([10, 255, 255])
    color_list = []
    color_list.append(lower_red)
    color_list.append(upper_red)
    dict['red2'] = color_list

    # 橙色
    lower_orange = np.array([11, 43, 46])
    upper_orange = np.array([25, 255, 255])
    color_list = []
    color_list.append(lower_orange)
    color_list.append(upper_orange)
    dict['orange'] = color_list

    # 黄色
    lower_yellow = np.array([26, 43, 46])
    upper_yellow = np.array([34, 255, 255])
    color_list = []
    color_list.append(lower_yellow)
    color_list.append(upper_yellow)
    dict['yellow'] = color_list

    # 绿色
    lower_green = np.array([35, 43, 46])
    upper_green = np.array([77, 255, 255])
    color_list = []
    color_list.append(lower_green)
    color_list.append(upper_green)
    dict['green'] = color_list

    # 青色
    lower_cyan = np.array([78, 43, 46])
    upper_cyan = np.array([99, 255, 255])
    color_list = []
    color_list.append(lower_cyan)
    color_list.append(upper_cyan)
    dict['cyan'] = color_list

    # 蓝色
    lower_blue = np.array([100, 43, 46])
    upper_blue = np.array([124, 255, 255])
    color_list = []
    color_list.append(lower_blue)
    color_list.append(upper_blue)
    dict['blue'] = color_list

    # 紫色
    lower_purple = np.array([125, 43, 46])
    upper_purple = np.array([155, 255, 255])
    color_list = []
    color_list.append(lower_purple)
    color_list.append(upper_purple)
    dict['purple'] = color_list

    return dict

# 颜色识别
def get_color(image):
    print('go in get_color')
    img_array = cv2.imdecode(np.fromfile(image, dtype=np.uint8), -1)
    kernel_4 = np.ones((4, 4), np.uint8)  # 4x4的卷积核
    hsv = cv2.cvtColor(img_array, cv2.COLOR_BGR2HSV)
    maxsum = -100
    color = None
    color_dict = get_color_list()
    print(color_dict)
    for key in color_dict:
        mask = cv2.inRange(hsv, color_dict[key][0], color_dict[key][1]) # mask是把HSV图片中在颜色范围内的区域变成白色,其它区域变成黑色
        cv2.imwrite(key + os.path.splitext(image)[-1], mask)
        erosion = cv2.erode(mask, kernel_4, iterations=1)
        erosion = cv2.erode(erosion, kernel_4, iterations=1)
        dilation = cv2.dilate(erosion, kernel_4, iterations=1)
        dilation = cv2.dilate(dilation, kernel_4, iterations=1)
        target = cv2.bitwise_and(img_array, img_array, mask=dilation)
        binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY)[1]
        # binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)[1]
        # binary = cv2.dilate(binary, None, iterations=2)
        cnts, hiera = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # cnts, hiera = cv2.findContours(binary.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
        sum = 0
        for c in cnts:
            sum += cv2.contourArea(c)
        if sum > maxsum:
            maxsum = sum
            color = key
    return color
方法 2: 深層学習モデル

自動車の ROI 画像にトレーニング済みの色分類モデルを使用すると、効果が大幅に向上します。

# 对机动车ROI图片按颜色分类
def classify_vehcolor(dir_path):
    result_dir = os.path.join(os.path.dirname(dir_path), 'color_results')
    if not os.path.exists(result_dir):
        os.mkdir(result_dir)
    color_list = dict_color.values()
    for color in color_list:
        color_dir = os.path.join(result_dir, color)
        if not os.path.exists(color_dir):
            os.mkdir(color_dir)
    classify_number = 0
    for root, dirs, files in os.walk(dir_path):
        for dir in dirs:
            result_dic = classify_color(os.path.join(root, dir))
            for key, value in result_dic.items():
                dst_path = os.path.join(result_dir, value)
                try:
                    shutil.move(key, dst_path)
                    classify_number += 1
                except Exception:
                    pass
        img_files = [file_name for file_name in files if is_image(file_name)]
        if len(img_files) != 0:
            result_dic = classify_color(root)
            for key, value in result_dic.items():
                dst_path = os.path.join(result_dir, value)
                try:
                    shutil.move(key, dst_path)
                    classify_number += 1
                except Exception:
                    pass
    return classify_number

日内分類

つまり、撮影シーンが昼か夜かを分類する。ここでは、画像の平均的な明るさを大まかな分類に使用していますが、実際の測定によると精度は高くありませんが、とりあえずはこの方法を予備クリーニングとして使用し、時間があるときにより良いアルゴリズムを見つけてください。

# 对图片进行昼夜分类,根据图片的平均亮度
def classify_day_or_night(dir_path):
    result_dir = os.path.join(os.path.dirname(dir_path), 'day_night_results')
    if not os.path.exists(result_dir):
        os.mkdir(result_dir)
    item_list = ['白天', '黑夜']
    for item in item_list:
        item_dir = os.path.join(result_dir, item)
        if not os.path.exists(item_dir):
            os.mkdir(item_dir)
    classify_number = 0
    for root, dirs, files in os.walk(dir_path):
        img_files = [file_name for file_name in files if is_image(file_name)]
        for file in img_files:
            file_path = os.path.join(root, file)
            rgb_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
            img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
            brightness_value = img.mean()
            print('brightness_value', brightness_value)
            if brightness_value > 95:
                key = '白天'
            else:
                key = '黑夜'
            dst_path = os.path.join(result_dir, key)
            try:
                shutil.move(file_path, dst_path)
                classify_number += 1
            except Exception:
                pass
    return classify_number

ツールインターフェースの表示

ここに画像の説明を挿入
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/jane_xing/article/details/123408175