python 去除图像中的框

news2024/11/25 19:52:35

最近在做图像标注,会出现以下的图片,需要去除其中的边框。
原始图像

1.思路

  1. 人工标注画框的范围P,并使用标注工具在画框上画一个点A。
  2. 获取点A的坐标和颜色。在范围P内,将与点A颜色相似的每一个点x的颜色,替换为点x上下(或左右)范围内若干个点的平均颜色。但是对于边缘部分,可能存在如下图所示的问题:
    边框存在问题
  3. 对边框的边缘部分Q进行额外处理。边框的颜色可能与点A的颜色有较大差异,因此需要利用其他方法进行处理。我使用异常值检测算法,因为Q中未在步骤2去除的一些残留点,与原始图片会存在较大差异,结合频度信息可以筛选出这些点,并得到以下的效果:
    在这里插入图片描述

2.代码实现

  1. 导包和必要的参数、模型:
from PIL import Image
import numpy as np
from sklearn.ensemble import IsolationForest
from collections import Counter

# 判断rgb相似度用,可以小一些
threhold=15
threhold_border=15

# 采样半径,可以设的小一些,可以根据边框的粗细来设定
redius=20
redius_border=20

# 对边框进行处理需要调整的参数
step_add=37
step_max=2000
step=0
all_outliers=[]
top_outlier_num=10

# 创建Isolation Forest模型
model = IsolationForest(contamination=0.05)  # 设置异常点的比例
  1. 辅助函数

#判断颜色是否相似
def my_similar(a,b):
    if sum([abs(x-y) for (x,y) in zip(list(a),list(b))])/3<threhold:
        return True
    return False

# 判断颜色是否相似
def my_similar_border(a,b_s):
    for b in b_s:
        if sum([abs(x-y) for (x,y) in zip(list(a),list(b)[0])])/3<threhold_border:
            return True
    return False

# 获取异常值,用于处理边框的边缘Q
def get_outlier(tmp,model):
    normal_point=[]
    unnormal_point=[]
    # 将数据传递给模型进行训练
    model.fit(tmp)

    # 获取每个数据点的预测标签,-1 表示异常点,1 表示正常点
    labels = model.predict(tmp)

    # 打印每个数据点的标签
    for i, label in enumerate(labels):
        if label == -1:
            unnormal_point.append(tmp[i])
        if label==1:
            normal_point.append(tmp[i])
    return normal_point,unnormal_point

# 在水平或处置方向上获取邻居节点,以便进行颜色替换
def get_right_neighborhood(target_color,neighborhood_x,neighborhood_y):
    diff_x=0
    diff_y=0
    
    for neighborhood in neighborhood_x:
        diff_x+=abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
    for neighborhood in neighborhood_y:
        diff_y+=abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
    if diff_x>diff_y:
        return neighborhood_x,1
    return neighborhood_y,2
  1. 主函数和必要的准备数据
########################################################################################
############################开始对区域P和点A进行人工指定################################
################################对应“思路”第1部分#####################################
########################################################################################

# 利用手动或利用labelimg等标注工具,
# 确定“思路”第1部分中的区域“P”
#人工框选画框的大致位置,需要包裹住画框
x_1=1427
y_1=723
x_2=2061
y_2=1363

# 利用手动或利用labelimg等标注工具,
# 确定“思路”第1部分中的点“A”
x = 1495 # 目标像素点的 x 坐标
y = 1294 # 目标像素点的 y 坐标

# 主要函数
def replace_color_around_point(image_path, x, y, radius=redius):
    
    # 采样步数
    step=0
    
    # 打开图像
    image = Image.open(image_path)
    pixels = image.load()

    # 获取图像的宽度和高度
    width, height = image.size

    ########################################################################################
    ############################开始对边框的内部节点进行处理################################
    ################################对应“思路”第2部分#####################################
    ########################################################################################
    # 获取目标像素点的颜色
    target_color = pixels[x, y]
    # 循环遍历图像中的每个像素点
    for i in range(x_1,x_2):
        for j in range(y_1,y_2):
            # 如果像素颜色与目标颜色相同,则替换为周围区域颜色的平均值
            if my_similar(pixels[i, j],target_color):
                # 计算周围水平和垂直区域的颜色平均值
                neighborhood_x = []
                neighborhood_y=[]
                
                for m in range(i - redius, i + radius + 1):
                        if 0 <= m < width:
                            neighborhood_x.append(pixels[m, j])
                            
                for n in range(j - redius, j + radius + 1):
                        if 0 <= n < height:
                            neighborhood_y.append(pixels[i, n])
                            
                neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                neighborhood=[n for n in neighborhood if not my_similar(n,target_color)]
                neighborhood = np.array(neighborhood)
                average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                average_color_part_1 = tuple(np.mean(neighborhood[0:int(len(neighborhood)/2)], axis=0, dtype=int))
                average_color_part_2 = tuple(np.mean(neighborhood[int(len(neighborhood)/2)+1:], axis=0, dtype=int))
                
                # 替换像素颜色
                pixels[i, j] = average_color
                
                # 如果是水平方向
                if direction==1:
                    for m in range(i - int(redius_border/3), i):
                        if 0 <= m < width:
                                pixels[m,j]=average_color_part_1

                    for m in range(i, i + int(redius_border/3) + 1):
                        if 0 <= m < width:
                                pixels[m,j]=average_color_part_2
                
                # 如果是垂直方向
                if direction==2:            
                    for n in range(j - int(redius_border/3), j):
                        if 0 <= n < height:
                                pixels[i,n]=average_color_part_1

                    for n in range(j ,j + int(redius_border/3) + 1):
                        if 0 <= n < height:
                                pixels[i,n]=average_color_part_2
                
                step+=1
                
                if step%step_add==0 and step<step_max:
                    normal_point,unnormal_point=get_outlier(neighborhood,model)
                    unnormal_point=[tuple(x) for x in unnormal_point]
                    all_outliers.extend(unnormal_point)

    ########################################################################################
    ############################开始对边框的边缘节点进行处理################################
    ################################对应“思路”第2部分#####################################
    ########################################################################################

    # 使用Counter来统计三元组的出现次数
    all_outlier_counts = Counter(all_outliers)

    # 获取出现次数最多的十个三元组,用来去边框
    top_outliers = all_outlier_counts.most_common(top_outlier_num)
    
    # 循环遍历图像中的每个像素点
    for i in range(x_1,x_2):
        for j in range(y_1,y_2):
            
            # 如果该点和异常点中的颜色相似,就进行替换
            if my_similar_border(pixels[i, j] ,top_outliers):
                # 计算周围水平和垂直区域的颜色平均值
                neighborhood_x = []
                neighborhood_y=[]
                
                for m in range(i - int(radius/3), i + int(radius/3) + 1):
                        if 0 <= m < width:
                            neighborhood_x.append(pixels[m, j])
                            
                for n in range(j - int(radius/3), j + int(radius/3) + 1):
                        if 0 <= n < height:
                            neighborhood_y.append(pixels[i, n])
                            
                neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                neighborhood=[n for n in neighborhood if not n in top_outliers]
                neighborhood = np.array(neighborhood)
                average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                
                # 替换像素颜色
                pixels[i, j] = average_color
                                               
    # 保存修改后的图像
    image.save(r"../data/bbb.jpg")
  1. 调用
image_path = r"../data/aaa.jpg"  # 替换为您的输入图像路径
replace_color_around_point(image_path, x, y)

3.存在的问题

  1. 在进行颜色替换时,仅仅使用了平均值(代码中的average_color相关内容),也许可以使用其他线性插值算法。
  2. 需要对参数进行精心调节,否则可能导致框内的图像会出现以下的“毛刺现象”,且无法把“框”完全去除:
    参数调节的不太好
    将threhold参数调小后,毛刺消失。也可以对其他参数进行调节。在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1177966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电机应用-直流有刷电机

直流有刷电机 直流有刷电机具有结构简单、易于控制、成本低等特点。 基本的直流有刷电机在电源和电机间只需要两根电缆&#xff0c;可以节省配线和连接器所需的空间&#xff0c;并降低电缆和连接器的成本。 还可以使用MOSFET/IGBT开关对直流有刷电机进行控制&#xff0c;给电机…

第五章:Testing Modules

文章目录 State and ProgramsTestability of State-Based Programsintrusively test 侵入性测试Non-intrusive test 非侵入测试java和其他工具的实践有限状态机进行单元测试(Unit testing with FSA)构建状态机步骤step1:识别 FSA 状态step2:确定某个状态下的可用操作step3:…

【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…

java 之数据类型的转换

文章目录 package javastudy;public class arraytest{public void ad(int a,int b) {System.out.printf("ab is %f",ab);}public static void main(String[] args) {arraytest arr new arraytest();arr.ad(1.0, 2);//arr.ad(1 , 2);} }当我们的方法的数据类型是int …

【数据结构与算法】二叉树(基本操作和几种特殊二叉树介绍)

二叉树的基本介绍&#xff0c;只讲基本算法&#xff1b;对于特殊二叉树的相关算法&#xff0c;如AVL树的旋转&#xff0c;以后有时间再写。 文章目录 一、基本概念二、基本操作2.1 二叉树的存储方式2.2 常见操作2.3 二叉树的遍历2.31 前序遍历2.32 中序遍历2.33 后序遍历2.34 层…

JavaScript作用域实战

● 首先&#xff0c;我们先创建一个函数&#xff0c;和以前一样&#xff0c;计算一个年龄的 function calcAge(birthYear) {const age 2037 - birthYear;return age; }● 然后我们创建一个全局变量&#xff0c;并调用这个函数 const firstName "IT知识一享"; cal…

遇到python程序是通过sh文件启动的,如何调试

说明 下载的源码总会遇到这样启动的&#xff1a; 并且发现shell文件内容很多&#xff0c;比较复杂&#xff0c;比如&#xff1a; 解决方案 这时候想要调试&#xff0c;可以通过端口连接的方式调试&#xff0c;具体方法如下&#xff1a; 在vscode调试按钮中添加远程附加调试…

Antv/G2 自定义tooltip鼠标悬浮提示信息

Antv/G2 提示 - Tooltip 教程 Tooltip 提示信息文档 chart.line().position(label*value).color(type).tooltip(type*value, (type:string, value:number) > { return {name: type,value: value%}}) });demo&#xff1a; <!DOCTYPE html> <html lang&quo…

最受欢迎的程序员副业排行榜TOP6

程序员接单的情况并不少见&#xff0c;因为程序员职业工种的特殊性&#xff0c;能够比较快的衔接上新项目和新技术&#xff0c;所以接私活做副业成了许多程序员的不二之选。 程序员的副业是指程序员在业余时间里从事与编程相关的兼职工作&#xff0c;或者是与技术相关的创业项…

[算法训练营] 回溯算法专题(三)

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

致:CSGO游戏搬砖人的一封信

最近大家还在坚持操作CSGO游戏搬砖项目不&#xff1f; 这个项目虽是稳赚项目&#xff0c;但也有行情好和行情不好的时候&#xff0c;平台的大中小各种活动的举办&#xff0c;都会对我们的项目造成一定影响。行情的上下波动势必然会影响卡价的波动&#xff0c;影响选品的快慢&a…

【SqlSever】日期类型转换

特殊类型日期转换 原始数据 12 28 2021 5:18PM 12 28 2021 6:08PM 12 29 2021 7:47AM 12 26 2021 9:00PM 02 9 2022 10:44AM 转换为&#xff1a; 2021-12-28 17:18:00.000 2021-12-28 18:08:00.000 2021-12-29 07:47:00.000 2021-12-26 21:00:00.000 2022-02-09 10:44:00…

70 内网安全-域横向内网漫游Socks代理隧道技术

目录 必要基础知识点:1.内外网简单知识2.内网1和内网2通信问题3.正向反向协议通信连接问题4.内网穿透代理隧道技术说明 演示案例:内网穿透Ngrok测试演示-两个内网通讯上线内网穿透Frp自建跳板测试-两个内网通讯上线CFS三层内网漫游安全测试演练-某CTF线下2019 涉及资源: 主要说…

Spring Boot + EasyUI Datebox和Datetimebox样例

使用EasyUI的Datebox和Datetimebox组件&#xff0c;并对其进行适当的改造&#xff0c;比如更改日期格式、设置默认值或者将当前时间设置为默认值。 一、运行结果 二、实现代码 1.代码框架 2.实现代码 SpringBootMainApplication.java: package com.xj.main;import org.spri…

Mysql数据库的备份和恢复及日志管理

一、数据备份概述 1.1 备份的分类 完全备份&#xff1a;整个数据库完整地进行备份 增量备份&#xff1a;在完全备份的基础之上&#xff0c;对后续新增的内容进行备份 冷备份&#xff1a;关机备份&#xff0c;停止mysql服务&#xff0c;然后进行备份 热备份&#xff1a;开机备…

【机器视觉--光学】工业相机成像原理

相机成像原理分为透镜成像原理和小孔成像原理&#xff0c;工业相机原理与透镜成像类似。 透镜成像原理 凸透镜的成像规律是 即&#xff1a;物距的倒数与像距的倒数之和等于焦距的倒数 对焦原理 工业相机镜头分为定焦、定倍、变焦镜头&#xff0c;常用的是定焦和定倍&#xff…

Android耗电量测试

背 / 景 / 介 / 绍 目前对于移动设备而言&#xff0c;电量是很重要的一个方面。现在大家使用手机基本每天都需要充电&#xff0c;所以用户也非常关注耗电的问题&#xff0c;如果应用设计不合理导致电量大量消耗&#xff0c;那么对于关注耗电的用户而言&#xff0c;这款应用将会…

EasyExcel实现动态表头功能

EasyExcel实现动态表头功能 开发过程中&#xff0c;大部分都会使用到导出报表功能&#xff0c;目前阶段会用得有 poi导出&#xff08;暂无&#xff09;&#xff0c; easyexcel导出&#xff08;官方文档&#xff0c;https://easyexcel.opensource.alibaba.com/docs/current/&am…

六大设计原则:构建优雅、可维护和可扩展的软件

六大设计原则&#xff1a;构建优雅、可维护和可扩展的软件 单一职责原则 (Single Responsibility Principle)开放封闭原则 (Open-Closed Principle)里氏替换原则 (Liskov Substitution Principle)依赖倒置原则 (Dependency Inversion Principle)接口隔离原则 (Interface Segreg…

【Linux】Shell命令行的简易实现(C语言实现)内键命令,普通命令

文章目录 0.准备工作1.大体框架 一、获取命令行二、解析命令行三、进程执行1.普通命令2.内建命令 四、完整代码&#xff1a; 0.准备工作 1.大体框架 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <u…