任务
现测量收集到一批目标色彩样本的光谱响应数据截图(图片保存在spectrum_screenshots文件夹内,截图样例见图1)。其中,一个样本的光数据是从波长360纳米(nm)到750纳米分别测量得到的对应光强度值(实数)。
图1所示光谱数据为:7.319(360nm),7.339(370nm),6.860(380nm),…,80.(750nm);Checksum值(所有波长上光谱强度值的和)为790.337。
要求:将486张光谱数据图片转成数值格式
所需工具
Python: 编程语言
cnocr: 一个中文OCR工具,用于从图片中提取文本
PIL (Python Imaging Library): 用于打开和处理图片
openpyxl: 用于在Excel中创建和编辑工作表
步骤一:安装必要的Python库
在开始之前,确保你已经安装了所有必要的Python库。你可以通过以下命令安装这些库:
pip install cnocr pillow openpyxl
步骤二:图像OCR识别
我们将使用cnocr库从光谱数据图片中提取文本。由于OCR提取出的文本格式可能不一致,我们需要对其进行清理和格式化。以下是处理这些文本的代码:
import os
import re
import cnocr
from PIL import Image
from openpyxl import Workbook
def remove_spaces_around_decimal(input_str):
result = []
l=len(input_str)
for i in range(1,l-1):
if input_str[i] == ' ' and input_str[i-1]=='.':
continue
if input_str[i] == ' ' and input_str[i + 1] == '.':
continue
if input_str[i] == '.' and input_str[i + 1] == '.':
continue
if (input_str[i]!='.' and input_str[i]!=' 'and(input_str[i]<'0' or input_str[i]>'9'))and input_str[i + 1] == '.':
continue
if (input_str[i]!='.' and input_str[i]!=' 'and(input_str[i]<'0' or input_str[i]>'9'))and input_str[i - 1] == '.':
continue
result.append(input_str[i])
return ''.join(result)
这个函数主要用来清理OCR识别出的文本,去除多余的空格和不必要的字符,确保后续的正则表达式能准确提取数值。
步骤三:提取光谱数值并存储
我们将光谱数据图片文件夹中的每张图片转换为对应的数值格式,并将其保存到Excel文件中。以下是实现这一任务的完整代码:
def extract_float_numbers_from_images(directory):
# 初始化 cnocr
ocr = cnocr.CnOcr()
# 创建一个 Excel 工作簿
wb = Workbook()
ws = wb.active
# 添加列标题
columns = ["Filename", "360nm", "370nm", "380nm", "390nm", "400nm", "410nm", "420nm", "430nm","440nm","450nm", "460nm", "470nm", "480nm",
"490nm", "500nm", "510nm", "520nm", "530nm", "540nm","550nm", "560nm", "570nm", "580nm", "590nm", "600nm", "610nm", "620nm",
"630nm", "640nm", "650nm", "660nm", "670nm", "680nm", "690nm", "700nm", "710nm", "720nm", "730nm", "740nm", "750nm", "Checksum"]
ws.append(columns)
# 使用正则表达式匹配文件名中的数字部分
pattern = r'\d+'
# 遍历指定目录下的所有文件
for filename in os.listdir(directory):
# 仅处理 JPEG 格式的文件
if filename.endswith(".jpg"):
# 从文件名中提取数字部分
match = re.match(pattern, filename)
if match:
file_number = match.group()
file_path = os.path.join(directory, filename)
# 使用 cnocr 提取文本
text = ocr.ocr(Image.open(file_path))
# 合并提取的文本
extracted_text = ''
for line in text:
if 'text' in line:
extracted_text += (line['text']+' ')
extracted_text = remove_spaces_around_decimal(extracted_text)
# 使用正则表达式匹配浮点数的模式
float_numbers = re.findall(r'\d+\.\d+', extracted_text)
# 创建一个列表,用于存储每行的数据
row_data = [filename] + float_numbers
# 如果提取的浮点数数量少于所需的列数,则补充空白
while len(row_data) < len(columns):
row_data.append("")
# 将文件名和提取的浮点数写入 Excel 表格
ws.append(row_data)
# 保存 Excel 文件
excel_filename = "extracted_float_numbers.xlsx"
wb.save(excel_filename)
print(f"Float numbers extracted from images and saved to {excel_filename}")
运行程序
将代码保存为一个Python脚本文件,并在命令行中运行:
python your_script_name.py
效果:
利用OCR技术从图片中提取光谱数据,并将其转换为数值格式存储在Excel中。这种方法可以用于各种场景下的数据提取和处理。
完整代码
import os
import re
import cnocr
from PIL import Image
from openpyxl import Workbook
#由于使用cnocr识别出的字符串存在很多格式上的问题
#我在多次写入表格查看以及输出对照数据之后,写了一个处理这些错误格式的函数,经过函数处理之后得到的字符串基本上都可以完美的经过正则表达式的处理得到41个浮点数
def remove_spaces_around_decimal(input_str):
result = []
l=len(input_str)
for i in range(1,l-1):
if input_str[i] == ' ' and input_str[i-1]=='.':
continue
if input_str[i] == ' ' and input_str[i + 1] == '.':
continue
if input_str[i] == '.' and input_str[i + 1] == '.':
continue
if (input_str[i]!='.' and input_str[i]!=' 'and(input_str[i]<'0' or input_str[i]>'9'))and input_str[i + 1] == '.':
continue
if (input_str[i]!='.' and input_str[i]!=' 'and(input_str[i]<'0' or input_str[i]>'9'))and input_str[i - 1] == '.':
continue
result.append(input_str[i])
return ''.join(result)
def extract_float_numbers_from_images(directory):
# 初始化 cnocr
ocr = cnocr.CnOcr()
# 创建一个 Excel 工作簿
wb = Workbook()
ws = wb.active
# 添加列标题
columns = ["Filename", "360nm", "370nm", "380nm", "390nm", "400nm", "410nm", "420nm", "430nm","440nm","450nm", "460nm", "470nm", "480nm",
"490nm", "500nm", "510nm", "520nm", "530nm", "540nm","550nm", "560nm", "570nm", "580nm", "590nm", "600nm", "610nm", "620nm",
"630nm", "640nm", "650nm", "660nm", "670nm", "680nm", "690nm", "700nm", "710nm", "720nm", "730nm", "740nm", "750nm", "Checksum"]
ws.append(columns)
# 使用正则表达式匹配文件名中的数字部分
pattern = r'\d+'
# 遍历指定目录下的所有文件
for filename in os.listdir(directory):
# 仅处理 JPEG 格式的文件
if filename.endswith(".jpg"):
# 从文件名中提取数字部分
match = re.match(pattern, filename)
if match:
file_number = match.group()
file_path = os.path.join(directory, filename)
# 使用 cnocr 提取文本
text = ocr.ocr(Image.open(file_path))
# 合并提取的文本
extracted_text = ''
for line in text:
if 'text' in line:
extracted_text += (line['text']+' ')
extracted_text = remove_spaces_around_decimal(extracted_text)
# 使用正则表达式匹配浮点数的模式
float_numbers = re.findall(r'\d+\.\d+', extracted_text)
# 创建一个列表,用于存储每行的数据
row_data = [filename] + float_numbers
# 如果提取的浮点数数量少于所需的列数,则补充空白
while len(row_data) < len(columns):
row_data.append("")
# 将文件名和提取的浮点数写入 Excel 表格
ws.append(row_data)
# 保存 Excel 文件
excel_filename = "extracted_float_numbers.xlsx"
wb.save(excel_filename)
print(f"Float numbers extracted from images and saved to {excel_filename}")
# 调用函数并传入图片所在的目录路径
extract_float_numbers_from_images(r'G:\spectrum_screenshots')