Support non-ascii characters

This commit is contained in:
Kenneth Estanislao
2026-06-14 20:18:56 +08:00
parent 3b69413d61
commit 834bc43768
8 changed files with 73 additions and 52 deletions
+38 -18
View File
@@ -1,18 +1,38 @@
import os
import cv2
import numpy as np
# Utility function to support unicode characters in file paths for reading
def imread_unicode(path, flags=cv2.IMREAD_COLOR):
return cv2.imdecode(np.fromfile(path, dtype=np.uint8), flags)
# Utility function to support unicode characters in file paths for writing
def imwrite_unicode(path, img, params=None):
root, ext = os.path.splitext(path)
if not ext:
ext = ".png"
result, encoded_img = cv2.imencode(ext, img, params if params is not None else [])
if not result:
return False
encoded_img.tofile(path)
return True
import os
import cv2
import numpy as np
# Utility function to support unicode characters in file paths for reading.
# OpenCV's cv2.imread() encodes the path with the locale ANSI code page on
# Windows, so it silently returns None for paths containing non-ASCII
# characters (Chinese, Japanese, Cyrillic, accents, ...). Reading the bytes
# through NumPy (which uses Python's unicode-aware file I/O) and decoding them
# in memory sidesteps that limitation. Returns None on failure, matching
# cv2.imread() so it stays a drop-in replacement.
def imread_unicode(path, flags=cv2.IMREAD_COLOR):
try:
data = np.fromfile(path, dtype=np.uint8)
if data.size == 0:
return None
return cv2.imdecode(data, flags)
except Exception:
return None
# Utility function to support unicode characters in file paths for writing.
# cv2.imwrite() has the same ANSI-path limitation, so we encode the image in
# memory and write the bytes out with NumPy's unicode-aware file I/O. Returns
# True/False like cv2.imwrite() so it stays a drop-in replacement.
def imwrite_unicode(path, img, params=None):
try:
root, ext = os.path.splitext(path)
if not ext:
ext = ".png"
result, encoded_img = cv2.imencode(ext, img, params if params is not None else [])
if not result:
return False
encoded_img.tofile(path)
return True
except Exception:
return False
+6 -6
View File
@@ -4,8 +4,8 @@ from typing import Any
import insightface
import threading
import cv2
import modules.globals
from modules import imread_unicode, imwrite_unicode
from tqdm import tqdm
from modules.typing import Frame
from modules.cluster_analysis import find_cluster_centroids, find_closest_centroid
@@ -254,7 +254,7 @@ def add_blank_map() -> Any:
def get_unique_faces_from_target_image() -> Any:
try:
modules.globals.source_target_map = []
target_frame = cv2.imread(modules.globals.target_path)
target_frame = imread_unicode(modules.globals.target_path)
many_faces = get_many_faces(target_frame)
if many_faces is None:
return None
@@ -290,7 +290,7 @@ def get_unique_faces_from_target_video() -> Any:
i = 0
for temp_frame_path in tqdm(temp_frame_paths, desc="Extracting face embeddings from frames"):
temp_frame = cv2.imread(temp_frame_path)
temp_frame = imread_unicode(temp_frame_path)
many_faces = get_many_faces(temp_frame)
if many_faces is None:
continue
@@ -343,7 +343,7 @@ def default_target_face():
x_min, y_min, x_max, y_max = best_face['bbox']
target_frame = cv2.imread(best_frame['location'])
target_frame = imread_unicode(best_frame['location'])
map['target'] = {
'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
'face' : best_face
@@ -359,7 +359,7 @@ def dump_faces(centroids: Any, frame_face_embeddings: list):
Path(temp_directory_path + f"/{i}").mkdir(parents=True, exist_ok=True)
for frame in tqdm(frame_face_embeddings, desc=f"Copying faces to temp/./{i}"):
temp_frame = cv2.imread(frame['location'])
temp_frame = imread_unicode(frame['location'])
j = 0
for face in frame['faces']:
@@ -367,5 +367,5 @@ def dump_faces(centroids: Any, frame_face_embeddings: list):
x_min, y_min, x_max, y_max = face['bbox']
if temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)].size > 0:
cv2.imwrite(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
imwrite_unicode(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
j += 1
+2 -2
View File
@@ -126,7 +126,7 @@ def process_video_in_memory(source_path: str, target_path: str, fps: float) -> b
Returns True on success, False on failure (caller should fall back to the
disk-based pipeline).
"""
import cv2
from modules import imread_unicode
from modules.face_analyser import get_one_face
from modules.utilities import (
get_video_dimensions,
@@ -139,7 +139,7 @@ def process_video_in_memory(source_path: str, target_path: str, fps: float) -> b
# --- Pre-load source face (needed by face_swapper in simple mode) ---
source_face = None
if source_path and os.path.exists(source_path):
source_img = cv2.imread(source_path)
source_img = imread_unicode(source_path)
if source_img is not None:
source_face = get_one_face(source_img)
del source_img
+5 -4
View File
@@ -10,6 +10,7 @@ import onnxruntime
import modules.globals
import modules.processors.frame.core
from modules import imread_unicode, imwrite_unicode
from modules.core import update_status
from modules.face_analyser import get_many_faces
from modules.typing import Frame, Face
@@ -407,7 +408,7 @@ def process_frames(
progress.update(1)
continue
temp_frame = cv2.imread(temp_frame_path)
temp_frame = imread_unicode(temp_frame_path)
if temp_frame is None:
print(
f"{NAME}: Warning: Failed to read frame {temp_frame_path}, skipping."
@@ -417,7 +418,7 @@ def process_frames(
continue
result_frame = process_frame(None, temp_frame)
cv2.imwrite(temp_frame_path, result_frame)
imwrite_unicode(temp_frame_path, result_frame)
if progress:
progress.update(1)
@@ -426,12 +427,12 @@ def process_image(
source_path: str | None, target_path: str, output_path: str
) -> None:
"""Processes a single image file."""
target_frame = cv2.imread(target_path)
target_frame = imread_unicode(target_path)
if target_frame is None:
print(f"{NAME}: Error: Failed to read target image {target_path}")
return
result_frame = process_frame(None, target_frame)
cv2.imwrite(output_path, result_frame)
imwrite_unicode(output_path, result_frame)
print(f"{NAME}: Enhanced image saved to {output_path}")
@@ -4,10 +4,9 @@ from typing import Any, List
import os
import threading
import cv2
import modules.globals
import modules.processors.frame.core
from modules import imread_unicode, imwrite_unicode
from modules.core import update_status
from modules.face_analyser import get_one_face
from modules.typing import Frame, Face
@@ -102,24 +101,24 @@ def process_frames(
source_path: str | None, temp_frame_paths: List[str], progress: Any = None
) -> None:
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
temp_frame = imread_unicode(temp_frame_path)
if temp_frame is None:
if progress:
progress.update(1)
continue
result = process_frame(None, temp_frame)
cv2.imwrite(temp_frame_path, result)
imwrite_unicode(temp_frame_path, result)
if progress:
progress.update(1)
def process_image(source_path: str | None, target_path: str, output_path: str) -> None:
target_frame = cv2.imread(target_path)
target_frame = imread_unicode(target_path)
if target_frame is None:
print(f"{NAME}: Error: Failed to read target image {target_path}")
return
result_frame = process_frame(None, target_frame)
cv2.imwrite(output_path, result_frame)
imwrite_unicode(output_path, result_frame)
print(f"{NAME}: Enhanced image saved to {output_path}")
@@ -4,10 +4,9 @@ from typing import Any, List
import os
import threading
import cv2
import modules.globals
import modules.processors.frame.core
from modules import imread_unicode, imwrite_unicode
from modules.core import update_status
from modules.face_analyser import get_one_face
from modules.typing import Frame, Face
@@ -102,24 +101,24 @@ def process_frames(
source_path: str | None, temp_frame_paths: List[str], progress: Any = None
) -> None:
for temp_frame_path in temp_frame_paths:
temp_frame = cv2.imread(temp_frame_path)
temp_frame = imread_unicode(temp_frame_path)
if temp_frame is None:
if progress:
progress.update(1)
continue
result = process_frame(None, temp_frame)
cv2.imwrite(temp_frame_path, result)
imwrite_unicode(temp_frame_path, result)
if progress:
progress.update(1)
def process_image(source_path: str | None, target_path: str, output_path: str) -> None:
target_frame = cv2.imread(target_path)
target_frame = imread_unicode(target_path)
if target_frame is None:
print(f"{NAME}: Error: Failed to read target image {target_path}")
return
result_frame = process_frame(None, target_frame)
cv2.imwrite(output_path, result_frame)
imwrite_unicode(output_path, result_frame)
print(f"{NAME}: Enhanced image saved to {output_path}")
+7 -6
View File
@@ -7,6 +7,7 @@ import numpy as np
import platform
import modules.globals
import modules.processors.frame.core
from modules import imread_unicode, imwrite_unicode
from modules.core import update_status
from modules.face_analyser import get_one_face, get_many_faces, default_source_face
from modules.typing import Face, Frame
@@ -917,7 +918,7 @@ def process_frames(
# Log the error but allow proceeding; subsequent check will stop processing.
else:
try:
source_img = cv2.imread(source_path)
source_img = imread_unicode(source_path)
if source_img is None:
# Specific error for file reading failure
update_status(f"Error reading source image file {source_path}. Please check the path and file integrity.", NAME)
@@ -957,7 +958,7 @@ def process_frames(
# Read the target frame
temp_frame = None
try:
temp_frame = cv2.imread(temp_frame_path)
temp_frame = imread_unicode(temp_frame_path)
if temp_frame is None:
print(f"{NAME}: Error: Could not read frame: {temp_frame_path}, skipping.")
if progress:
@@ -995,7 +996,7 @@ def process_frames(
# Write the result back to the same frame path with optimized compression
try:
# Use PNG compression level 3 (faster) instead of default 9
write_success = cv2.imwrite(temp_frame_path, result_frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])
write_success = imwrite_unicode(temp_frame_path, result_frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])
if not write_success:
print(f"{NAME}: Error: Failed to write processed frame to {temp_frame_path}")
except Exception as write_e:
@@ -1025,7 +1026,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
# Read target first
try:
target_frame = cv2.imread(target_path)
target_frame = imread_unicode(target_path)
if target_frame is None:
update_status(f"Error: Could not read target image: {target_path}", NAME)
return
@@ -1044,7 +1045,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
else: # Simple mode
try:
source_img = cv2.imread(source_path)
source_img = imread_unicode(source_path)
if source_img is None:
update_status(f"Error: Could not read source image: {source_path}", NAME)
return
@@ -1060,7 +1061,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
# Write the result if processing was successful
if result is not None:
write_success = cv2.imwrite(output_path, result)
write_success = imwrite_unicode(output_path, result)
if write_success:
update_status(f"Output image saved to: {output_path}", NAME)
else:
+5 -4
View File
@@ -73,6 +73,7 @@ from modules.utilities import (
is_image,
is_video,
)
from modules import imread_unicode
from modules.video_capture import VideoCapturer
if platform.system() == "Windows":
@@ -988,7 +989,7 @@ class PreviewWindow(QWidget):
from modules.processors.frame.core import get_frame_processors_modules as _gfpm
for fp in _gfpm(modules.globals.frame_processors):
temp_frame = fp.process_frame(
get_one_face(cv2.imread(modules.globals.source_path)), temp_frame
get_one_face(imread_unicode(modules.globals.source_path)), temp_frame
)
# Fit to current widget size while preserving aspect ratio.
h, w = temp_frame.shape[:2]
@@ -1071,7 +1072,7 @@ class _ProcessingWorker(QThread):
and modules.globals.source_path != last_source_path
):
last_source_path = modules.globals.source_path
source_image = get_one_face(cv2.imread(modules.globals.source_path))
source_image = get_one_face(imread_unicode(modules.globals.source_path))
det_count += 1
if det_count % det_interval == 0:
@@ -1337,7 +1338,7 @@ class MapperDialog(QDialog):
)
if not path:
return
cv2_img = cv2.imread(path)
cv2_img = imread_unicode(path)
face = get_one_face(cv2_img)
if face is None:
self.set_status("Face could not be detected in last upload!")
@@ -1442,7 +1443,7 @@ class LiveMapperDialog(QDialog):
)
if not path:
return
cv2_img = cv2.imread(path)
cv2_img = imread_unicode(path)
face = get_one_face(cv2_img)
if face is None:
self.set_status("Face could not be detected in last upload!")