SYSTEM: You are a Python programmer tasked with refactoring code. You are proficient in Python 3.12 and use modern features where appropriate. Your code is clear, easy to read, and free of unnecessary verbosity. You use single-line docstrings and occasional comments for documentation. Often, the code you receive is just one part of a larger program. USER: Use the is_color_image function for the color/grayscale detection in the process file function. def is_color_image(
    img: np.ndarray,
    diff_threshold: int = Config.COLORDIFF_THRESHOLD,
    fraction_threshold: float = Config.FRACTION_COLORED_PIXELS_THRESHOLD
) -> bool:
    """Determine if an image is color based on RGB channel differences."""
    # Check if the image has three channels (RGB)
    if img.ndim != 3 or img.shape[2] != 3:
        return False

    # Calculate the peak-to-peak (max - min) difference across the RGB channels for each pixel
    max_diff = np.ptp(img, axis=2)

    # Compute the fraction of pixels where the max difference exceeds the threshold
    fraction_colored = np.mean(max_diff > diff_threshold)

    # Determine if the image meets or exceeds the required fraction of colored pixels
    return fraction_colored >= fraction_threshold        def process_file(path: Path, start_time, total_files, image_processor: 'ImageProcessor', temp_folder: Path, resize=False, auto_correct_and_resize=False) -> None:
    """Process a single image file."""
    if shared_state.stop_event.is_set():
        return

    if not is_valid_image(path):
        log_error(f"Invalid image file: {path}")
        with shared_state.processed_files_lock:
            shared_state.processed_files_count += 1
        update_status(start_time, shared_state.processed_files_count, total_files)
        return

    try:
        img = np.array(open_and_convert_image(path))
    except (OSError, ValueError) as e:
        log_error(f"Error reading image {path}: {e}")
        with shared_state.processed_files_lock:
            shared_state.processed_files_count += 1
        update_status(start_time, shared_state.processed_files_count, total_files)
        return

    relative_path = path.relative_to(Config.INPUT_FOLDER)
    temp_output_path = temp_folder / relative_path
    temp_output_path = temp_output_path.with_suffix('.png')
    temp_output_path.parent.mkdir(parents=True, exist_ok=True)

    if auto_correct_and_resize:
        if img.ndim == 2 or (img.ndim == 3 and img.shape[2] == 1):
            intermediate_path, _, _ = process_grayscale_image(img, path, image_processor, temp_folder)
        else:
            intermediate_path, _ = process_color_image(img, path, image_processor, temp_folder)
        temp_output_path = resize_image(intermediate_path, temp_output_path)
    elif resize:
        temp_output_path = resize_image(path, temp_output_path)
    else:
        if img.ndim == 2 or (img.ndim == 3 and img.shape[2] == 1):
            temp_output_path, _, _ = process_grayscale_image(img, path, image_processor, temp_folder)
        else:
            temp_output_path, _ = process_color_image(img, path, image_processor, temp_folder)

    final_output_path = Config.OUTPUT_FOLDER / relative_path
    final_output_path.parent.mkdir(parents=True, exist_ok=True)

    if app.RESIZE_FORMAT.get() == 'jpg':
        final_output_path = final_output_path.with_suffix('.jpg')
        convert_png_to_jpg(temp_output_path, final_output_path)
    else:
        final_output_path = final_output_path.with_suffix('.png')
        shutil.move(str(temp_output_path), str(final_output_path))

    with shared_state.processed_files_lock:
        shared_state.processed_files_count += 1
    update_status(start_time, shared_state.processed_files_count, total_files)