I have high number of JPG images in specific folder that I want to keep only #c7d296
color in my images and fill all other remaining areas in images with white color
.
for this I can't use Photoshop because I have high number of JPG images and it get me a lot of time! (about 29000 JPG images
).
for this I should use color range tool
in python script.
my images are like following sample:
I wrote following script for this process:
import cv2
import os
import numpy as np
import keyboard
def keep_color_only(input_file, output_directory, color_range, fuzziness):
try:
# Read the input image
img = cv2.imread(input_file)
# Convert image to HSV color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Define lower and upper bounds for the color range
lower_color = np.array(color_range[0])
upper_color = np.array(color_range[1])
# Threshold the HSV image to get only desired colors
mask = cv2.inRange(hsv, lower_color, upper_color)
# Invert the mask
mask_inv = cv2.bitwise_not(mask)
# Create a white background image
white_background = np.full_like(img, (255, 255, 255), dtype=np.uint8)
# Combine the original image with the white background using the mask
result = cv2.bitwise_and(img, img, mask=mask)
result = cv2.bitwise_or(result, white_background, mask=mask_inv)
# Output file path
output_file = os.path.join(output_directory, os.path.basename(input_file))
# Save the resulting image
cv2.imwrite(output_file, result)
except Exception as e:
print(f"Error processing {input_file}: {str(e)}")
def process_images(input_directory, output_directory, color_range, fuzziness):
# Create output directory if it doesn't exist
if not os.path.exists(output_directory):
os.makedirs(output_directory)
# Process each JPG file in the input directory
for filename in os.listdir(input_directory):
if filename.lower().endswith('.jpg'):
input_file = os.path.join(input_directory, filename)
keep_color_only(input_file, output_directory, color_range, fuzziness)
# Check for 'F7' key press to stop the process
if keyboard.is_pressed('F7'):
print("Process stopped by user.")
return
def main():
input_directory = r'E:\Desktop\inf\CROP'
output_directory = r'E:\Desktop\inf\OUTPUT'
# Color range in HSV format
color_range = [(75, 90, 160), (95, 255, 255)] # Lower and upper bounds for HSV color range
fuzziness = 80
process_images(input_directory, output_directory, color_range, fuzziness)
print("Color removal completed.")
if __name__ == "__main__":
main()
Note that fuzziness
of color range must set on 80
script working good but whole of output images fill by white color. this mean output images just have a empty white screen and no any #c7d296 color area keep
!
where is my script problem?
I know you tagged with python
but this is miles simpler with ImageMagick which can be installed on macOS, Linux and Windows for free.
So, basically you want a command like this:
magick 3KPrGAEl.jpg -fill white -fuzz 8% +opaque "#c7d296" result.jpg
That says... "take your input image, and fill with white, anything that is not within 8% of your green colour in the RGB colour cube, save the result as result.jpg
"
In case anyone is struggling with what 8% means, it works like this... The RGB colour cube has sides of length 256. So its diagonal, I mean the line running from pure black to pure white, has length 256 * √3 and that is considered 100% as it is the longest possible distance between two colours. Anything else is a percentage of that length. So, with this method you are using an ice-cream scoop, to scoop out a ball (or sphere) of the radius you desire (as specified by the fuzz) from the RGB colour cube centred on your #c7d296.
Unfortunately, JPEG is a really poor choice for blocky, computer-generated images and it blurs colours and details and makes a heck of a mess, leaving artefacts everywhere. If you could get the images as PNG, you would do better.
Alternatively, you could run a 3x3 median filter to remove small artefacts:
magick 3KPrGAEl.jpg -fill white -fuzz 8% +opaque '#c7d296' -statistic median 3 result.png
If you need to remove larger artefacts, change the 3 to a 5 or 7. Note though that you will start to lose the edges of your yellow-greenish shape if you do that.
Once you have that command working, you can then adapt it to do all your images, using mogrify
. Let's assume you want the output files in a directory called OUTPUT
, you can do all your images in one go with:
mkdir OUTPUT
magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296" *.jpg
If you want to speed things up, you should be using all those CPU cores you paid Intel so handsomely for. In general, that means using multi-processing. The simplest way to do that without hand-crafting any code is to use GNU Parallel.
The command would look like this:
parallel -N 10 'magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296"' ::: *.jpg
If that causes errors with too many files, you would need a pipe:
find . -name "*.jpg" -print0 | parallel -0 -N 10 'magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296"'
On Windows, you will need to install MSYS2 or WSL to use GNU Parallel.
Or, if your files are named numerically, you can simply do, say 10, parallel processes by picking filenames. For example, if your files are numbered 0..29000.jpg You could do all the files ending in 0 in one job, all the files ending in 1 in another job and so on, running the jobs in parallel:
magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296" *0.jpg &
magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296" *1.jpg &
magick mogrify -path OUTPUT -fill white -fuzz 8% +opaque "#c7d296" *2.jpg &
Note you should consider multiprocessing with your Python solution anyway. Example here.