first commit
1
.codex/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
tmp/
|
||||
184
.gitignore
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyc
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
tmp/
|
||||
develop-eggs/
|
||||
dist/
|
||||
wheels_dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
requirements.txt
|
||||
setup.py
|
||||
x_anylabeling_cvhub520.egg-info
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other info into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
mlruns/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# Profiling
|
||||
*.pclprof
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
.idea
|
||||
.github
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
venv-*/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# VSCode project settings
|
||||
.vscode/
|
||||
.devcontainer/
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# datasets and projects
|
||||
/datasets
|
||||
data
|
||||
runs/
|
||||
wandb/
|
||||
zipped_models/
|
||||
.DS_Store
|
||||
|
||||
# Generated UI files
|
||||
*_ui.py
|
||||
anylabeling/app_info.py-*
|
||||
|
||||
# Neural Network weights -----------------------------------------------------------------------------------------------
|
||||
weights/
|
||||
*.weights
|
||||
*.pt
|
||||
*.ts
|
||||
*.pb
|
||||
*.onnx
|
||||
*.engine
|
||||
*.mlmodel
|
||||
*.mlpackage
|
||||
*.torchscript
|
||||
*.tflite
|
||||
*.h5
|
||||
*.mnn
|
||||
*_saved_model/
|
||||
*_web_model/
|
||||
*_openvino_model/
|
||||
*_paddle_model/
|
||||
*_ncnn_model/
|
||||
*_imx_model/
|
||||
pnnx*
|
||||
*.rknn
|
||||
|
||||
# calibration image
|
||||
calibration_*.npy
|
||||
197
classify_images.py
Normal file
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
gavin 2026-01-06
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Iterable, List, Tuple
|
||||
|
||||
from PIL import Image, ImageChops, UnidentifiedImageError
|
||||
|
||||
|
||||
def is_color_image(image_path: Path, tolerance: int = 3) -> bool:
|
||||
"""
|
||||
Return True if the image contains color information beyond grayscale.
|
||||
|
||||
The tolerance parameter allows minor compression artifacts without
|
||||
misclassifying grayscale images as color.
|
||||
"""
|
||||
with Image.open(image_path) as img:
|
||||
rgb = img.convert("RGB")
|
||||
r, g, b = rgb.split()
|
||||
diff_rg = ImageChops.difference(r, g)
|
||||
diff_rb = ImageChops.difference(r, b)
|
||||
max_diff = max(diff_rg.getextrema()[1], diff_rb.getextrema()[1])
|
||||
return max_diff > tolerance
|
||||
|
||||
|
||||
def iter_image_files(directory: Path) -> List[Path]:
|
||||
return [path for path in sorted(directory.iterdir()) if path.is_file()]
|
||||
|
||||
|
||||
def unique_destination(target_dir: Path, filename: str) -> Path:
|
||||
candidate = target_dir / filename
|
||||
if not candidate.exists():
|
||||
return candidate
|
||||
|
||||
stem = candidate.stem
|
||||
suffix = candidate.suffix
|
||||
index = 1
|
||||
while True:
|
||||
candidate = target_dir / f"{stem}_{index}{suffix}"
|
||||
if not candidate.exists():
|
||||
return candidate
|
||||
index += 1
|
||||
|
||||
|
||||
def classify_images(
|
||||
input_dir: Path,
|
||||
color_dir: Path,
|
||||
bw_dir: Path,
|
||||
*,
|
||||
move_files: bool = False,
|
||||
tolerance: int = 3,
|
||||
dry_run: bool = False,
|
||||
) -> Tuple[int, int, int]:
|
||||
"""
|
||||
Classify images in input_dir into color or black/white destinations.
|
||||
|
||||
Returns a tuple of (color_count, bw_count, skipped_count).
|
||||
"""
|
||||
color_dir.mkdir(parents=True, exist_ok=True)
|
||||
bw_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
color_count = bw_count = skipped_count = 0
|
||||
image_paths = iter_image_files(input_dir)
|
||||
total = len(image_paths)
|
||||
|
||||
def print_progress(done: int) -> None:
|
||||
if total == 0:
|
||||
return
|
||||
if done % 10 != 0 and done != total:
|
||||
return
|
||||
percent = done / total * 100
|
||||
print(f"处理进度: {done}/{total} ({percent:5.1f}%)")
|
||||
|
||||
processed = 0
|
||||
for image_path in image_paths:
|
||||
try:
|
||||
has_color = is_color_image(image_path, tolerance=tolerance)
|
||||
except (UnidentifiedImageError, OSError) as exc:
|
||||
print(f"跳过无法读取的文件: {image_path} ({exc})")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
target_dir = color_dir if has_color else bw_dir
|
||||
destination = unique_destination(target_dir, image_path.name)
|
||||
|
||||
if dry_run:
|
||||
action = "彩色" if has_color else "黑白"
|
||||
print(f"[dry-run] {image_path} -> {action} ({destination.name})")
|
||||
else:
|
||||
if move_files:
|
||||
shutil.move(str(image_path), destination)
|
||||
else:
|
||||
shutil.copy2(image_path, destination)
|
||||
|
||||
if has_color:
|
||||
color_count += 1
|
||||
else:
|
||||
bw_count += 1
|
||||
|
||||
processed += 1
|
||||
print_progress(processed)
|
||||
|
||||
return color_count, bw_count, skipped_count
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
default_color_dir = Path("data") / f"c-{timestamp}"
|
||||
default_bw_dir = Path("data") / f"b-{timestamp}"
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="将图片按彩色或黑白分类到指定目录。"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--input-dir",
|
||||
type=Path,
|
||||
default=Path("data/color/mix"),
|
||||
help="待分类的图片目录(默认: data/color/mix)。",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--color-dir",
|
||||
type=Path,
|
||||
default=default_color_dir,
|
||||
help=f"彩色图片输出目录(默认: {default_color_dir})。",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--bw-dir",
|
||||
type=Path,
|
||||
default=default_bw_dir,
|
||||
help=f"黑白/灰阶图片输出目录(默认: {default_bw_dir})。",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--tolerance",
|
||||
type=int,
|
||||
default=3,
|
||||
help="颜色通道差异阈值,越大越宽松(默认: 3)。",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--move",
|
||||
dest="move_files",
|
||||
action="store_true",
|
||||
help="移动文件而非复制,谨慎使用。",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="仅输出分类结果,不执行复制/移动。",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def exit_with_usage(parser: argparse.ArgumentParser, message: str) -> None:
|
||||
# 额外打印 usage,便于用户看到用法提示
|
||||
parser.print_usage()
|
||||
parser.exit(2, f"{parser.prog}: error: {message}\n")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input_dir.exists():
|
||||
exit_with_usage(parser, f"输入目录不存在: {args.input_dir}")
|
||||
if not args.input_dir.is_dir():
|
||||
exit_with_usage(parser, f"输入路径不是目录: {args.input_dir}")
|
||||
if args.tolerance < 0:
|
||||
exit_with_usage(parser, "tolerance 需为非负整数。")
|
||||
|
||||
color_count, bw_count, skipped_count = classify_images(
|
||||
args.input_dir,
|
||||
args.color_dir,
|
||||
args.bw_dir,
|
||||
move_files=args.move_files,
|
||||
tolerance=args.tolerance,
|
||||
dry_run=args.dry_run,
|
||||
)
|
||||
|
||||
summary = (
|
||||
f"彩色: {color_count} 张,"
|
||||
f"黑白/灰阶: {bw_count} 张,"
|
||||
f"跳过: {skipped_count} 张。"
|
||||
)
|
||||
print(summary)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
color/all/1766546823370.jpg
Executable file
|
After Width: | Height: | Size: 186 KiB |
BIN
color/all/1766546963038.jpg
Executable file
|
After Width: | Height: | Size: 233 KiB |
BIN
color/all/1766546973198.jpg
Executable file
|
After Width: | Height: | Size: 244 KiB |
BIN
color/all/1766547003755.jpg
Executable file
|
After Width: | Height: | Size: 483 KiB |
BIN
color/all/1766547051961.jpg
Executable file
|
After Width: | Height: | Size: 187 KiB |
BIN
color/all/1766547114475.jpg
Executable file
|
After Width: | Height: | Size: 160 KiB |
BIN
color/all/1766547160890.jpg
Executable file
|
After Width: | Height: | Size: 472 KiB |
BIN
color/all/1766547179517.jpg
Executable file
|
After Width: | Height: | Size: 68 KiB |
BIN
color/all/1766547272322.jpg
Executable file
|
After Width: | Height: | Size: 515 KiB |
BIN
color/all/1766547307974.jpg
Executable file
|
After Width: | Height: | Size: 420 KiB |
BIN
color/all/1766547313246.jpg
Executable file
|
After Width: | Height: | Size: 473 KiB |
BIN
color/all/1766547318804.jpg
Executable file
|
After Width: | Height: | Size: 454 KiB |
BIN
color/all/1766555796381.jpg
Executable file
|
After Width: | Height: | Size: 569 KiB |
BIN
color/all/1766557282658.jpg
Executable file
|
After Width: | Height: | Size: 246 KiB |
BIN
color/all/1766557300155.jpg
Executable file
|
After Width: | Height: | Size: 112 KiB |
BIN
color/all/1766557361496.jpg
Executable file
|
After Width: | Height: | Size: 231 KiB |
BIN
color/all/1766557441320.jpg
Executable file
|
After Width: | Height: | Size: 207 KiB |
BIN
color/all/1766557453295.jpg
Executable file
|
After Width: | Height: | Size: 184 KiB |
BIN
color/all/1766557465954.jpg
Executable file
|
After Width: | Height: | Size: 404 KiB |
BIN
color/all/1766557475619.jpg
Executable file
|
After Width: | Height: | Size: 249 KiB |
BIN
color/all/1766557606202.jpg
Executable file
|
After Width: | Height: | Size: 249 KiB |
BIN
color/all/1766557692708.jpg
Executable file
|
After Width: | Height: | Size: 73 KiB |
BIN
color/all/1766557715487.jpg
Executable file
|
After Width: | Height: | Size: 372 KiB |
BIN
color/all/1766557781134.jpg
Executable file
|
After Width: | Height: | Size: 309 KiB |
BIN
color/all/1766557792375.jpg
Executable file
|
After Width: | Height: | Size: 175 KiB |
BIN
color/all/1766557936527.jpg
Executable file
|
After Width: | Height: | Size: 423 KiB |
BIN
color/all/1766558040177.jpg
Executable file
|
After Width: | Height: | Size: 452 KiB |
BIN
color/all/1766558042480.jpg
Executable file
|
After Width: | Height: | Size: 410 KiB |
BIN
color/all/1766558219464.jpg
Executable file
|
After Width: | Height: | Size: 104 KiB |
BIN
color/all/1766558279429.jpg
Executable file
|
After Width: | Height: | Size: 44 KiB |
BIN
color/all/1766558284649.jpg
Executable file
|
After Width: | Height: | Size: 149 KiB |
BIN
color/all/1766558312913.jpg
Executable file
|
After Width: | Height: | Size: 409 KiB |
BIN
color/all/1766558374306.jpg
Executable file
|
After Width: | Height: | Size: 272 KiB |
BIN
color/all/1766558480272.jpg
Executable file
|
After Width: | Height: | Size: 130 KiB |
BIN
color/all/1766558584797.jpg
Executable file
|
After Width: | Height: | Size: 99 KiB |
BIN
color/all/1766558597721.jpg
Executable file
|
After Width: | Height: | Size: 200 KiB |
BIN
color/all/1766558608508.jpg
Executable file
|
After Width: | Height: | Size: 120 KiB |
BIN
color/all/1766558618637.jpg
Executable file
|
After Width: | Height: | Size: 335 KiB |
BIN
color/all/1766558727858.jpg
Executable file
|
After Width: | Height: | Size: 181 KiB |
BIN
color/all/1766558794738.jpg
Executable file
|
After Width: | Height: | Size: 351 KiB |
BIN
color/all/1766558905412.jpg
Executable file
|
After Width: | Height: | Size: 302 KiB |
BIN
color/all/1766558910399.jpg
Executable file
|
After Width: | Height: | Size: 435 KiB |
BIN
color/all/1766558915106.jpg
Executable file
|
After Width: | Height: | Size: 122 KiB |
BIN
color/all/1766559024843.jpg
Executable file
|
After Width: | Height: | Size: 325 KiB |
BIN
color/all/1766559054992.jpg
Executable file
|
After Width: | Height: | Size: 78 KiB |
BIN
color/all/1766559092841.jpg
Executable file
|
After Width: | Height: | Size: 280 KiB |
BIN
color/all/1766559097931.jpg
Executable file
|
After Width: | Height: | Size: 350 KiB |
BIN
color/all/1766559139009.jpg
Executable file
|
After Width: | Height: | Size: 490 KiB |
BIN
color/all/1766559186952.jpg
Executable file
|
After Width: | Height: | Size: 407 KiB |
BIN
color/all/1766559246213.jpg
Executable file
|
After Width: | Height: | Size: 382 KiB |
BIN
color/all/1766559361592.jpg
Executable file
|
After Width: | Height: | Size: 262 KiB |
BIN
color/all/1766559479078.jpg
Executable file
|
After Width: | Height: | Size: 218 KiB |
BIN
color/all/1766559513120.jpg
Executable file
|
After Width: | Height: | Size: 296 KiB |
BIN
color/all/1766559534032.jpg
Executable file
|
After Width: | Height: | Size: 94 KiB |
BIN
color/all/1766559607894.jpg
Executable file
|
After Width: | Height: | Size: 67 KiB |
BIN
color/all/1766559626222.jpg
Executable file
|
After Width: | Height: | Size: 74 KiB |
BIN
color/all/1766559630977.jpg
Executable file
|
After Width: | Height: | Size: 253 KiB |
BIN
color/all/1766559643505.jpg
Executable file
|
After Width: | Height: | Size: 416 KiB |
BIN
color/all/1766559652773.jpg
Executable file
|
After Width: | Height: | Size: 390 KiB |
BIN
color/all/1766559685347.jpg
Executable file
|
After Width: | Height: | Size: 385 KiB |
BIN
color/all/1766559688222.jpg
Executable file
|
After Width: | Height: | Size: 463 KiB |
BIN
color/all/1766559703434.jpg
Executable file
|
After Width: | Height: | Size: 233 KiB |
BIN
color/all/1766559725447.jpg
Executable file
|
After Width: | Height: | Size: 346 KiB |
BIN
color/all/1766559761498.jpg
Executable file
|
After Width: | Height: | Size: 111 KiB |
BIN
color/all/1766559766103.jpg
Executable file
|
After Width: | Height: | Size: 243 KiB |
BIN
color/all/1766559774938.jpg
Executable file
|
After Width: | Height: | Size: 254 KiB |
BIN
color/all/1766559808454.jpg
Executable file
|
After Width: | Height: | Size: 121 KiB |
BIN
color/all/1766559821478.jpg
Executable file
|
After Width: | Height: | Size: 294 KiB |
BIN
color/all/1766559875190.jpg
Executable file
|
After Width: | Height: | Size: 120 KiB |
BIN
color/all/1766559880115.jpg
Executable file
|
After Width: | Height: | Size: 348 KiB |
BIN
color/all/1766559984546.jpg
Executable file
|
After Width: | Height: | Size: 409 KiB |
BIN
color/all/1766560008003.jpg
Executable file
|
After Width: | Height: | Size: 384 KiB |
BIN
color/all/1766560073725.jpg
Executable file
|
After Width: | Height: | Size: 294 KiB |
BIN
color/all/1766560136551.jpg
Executable file
|
After Width: | Height: | Size: 384 KiB |
BIN
color/all/1766560192729.jpg
Executable file
|
After Width: | Height: | Size: 375 KiB |
BIN
color/all/1766560286331.jpg
Executable file
|
After Width: | Height: | Size: 78 KiB |
BIN
color/all/1766560363764.jpg
Executable file
|
After Width: | Height: | Size: 175 KiB |
BIN
color/all/1766560871532.jpg
Executable file
|
After Width: | Height: | Size: 278 KiB |
BIN
color/all/1766561104926.jpg
Executable file
|
After Width: | Height: | Size: 716 KiB |
BIN
color/all/1766561125081.jpg
Executable file
|
After Width: | Height: | Size: 178 KiB |
BIN
color/all/1766561137087.jpg
Executable file
|
After Width: | Height: | Size: 308 KiB |
BIN
color/all/1766561157928.jpg
Executable file
|
After Width: | Height: | Size: 167 KiB |
BIN
color/all/1766561211322.jpg
Executable file
|
After Width: | Height: | Size: 306 KiB |
BIN
color/all/1766561348340.jpg
Executable file
|
After Width: | Height: | Size: 296 KiB |
BIN
color/all/1766561380725.jpg
Executable file
|
After Width: | Height: | Size: 214 KiB |
BIN
color/all/1766561544368.jpg
Executable file
|
After Width: | Height: | Size: 150 KiB |
BIN
color/all/1766561594999.jpg
Executable file
|
After Width: | Height: | Size: 86 KiB |
BIN
color/all/1766561610929.jpg
Executable file
|
After Width: | Height: | Size: 354 KiB |
BIN
color/all/1766561659869.jpg
Executable file
|
After Width: | Height: | Size: 334 KiB |
BIN
color/all/1766561662402.jpg
Executable file
|
After Width: | Height: | Size: 381 KiB |
BIN
color/all/1766561725764.jpg
Executable file
|
After Width: | Height: | Size: 278 KiB |
BIN
color/all/1766561829411.jpg
Executable file
|
After Width: | Height: | Size: 146 KiB |
BIN
color/all/1766561844626.jpg
Executable file
|
After Width: | Height: | Size: 261 KiB |
BIN
color/all/1766561921674.jpg
Executable file
|
After Width: | Height: | Size: 129 KiB |
BIN
color/all/1766561952538.jpg
Executable file
|
After Width: | Height: | Size: 521 KiB |
BIN
color/all/1766562035578.jpg
Executable file
|
After Width: | Height: | Size: 515 KiB |
BIN
color/all/1766562037860.jpg
Executable file
|
After Width: | Height: | Size: 434 KiB |