Reputation: 51
I'm trying to transfer pixel value from one image and transferring it to other image. so, basically I have 2 images and my goal is to transfer colors of img1 to 2 according to the regions.
link to img1 img2 and expected image
here I am aware to extract color channel out of an image , but I am not able to achieve the required result. I'll highly appreciate any help. my approach:
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
os.chdir('/kaggle/input/maskedoutput')
stroke_list = natsorted(os.listdir())
for i,v in enumerate(stroke_list):
image = cv2.imread(v, cv2.IMREAD_UNCHANGED)
if image.shape[2] == 4:
a1 = ~image[:,:,3]
image = cv2.add(cv2.merge([a1,a1,a1,a1]), image)
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
else:
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
plt.imshow((image))
plt.show()
copy = image.copy()
kernel = np.ones((15,15), np.uint8)
closing = cv2.morphologyEx(copy, cv2.MORPH_CLOSE, kernel)
img_erode = cv2.erode(closing, kernel, iterations=1)# to supress black outline
height, width, channel = img_erode.shape
for x1 in range(0,width):
for y1 in range(0,height):
channels_x1y1 = img_erode[y1,x1]
os.chdir('/kaggle/input/maskstrokes')
output = natsorted(os.listdir())
for idx,v1 in enumerate(output):
if(v==v1):
print(v, v1)
img_out = cv2.imread(v1, cv2.IMREAD_UNCHANGED)
subtracted = cv2.subtract(img_out, img_erode)
else:
continue
plt.imshow(cv2.cvtColor(subtracted, cv2.COLOR_BGR2RGB))
plt.show()
here i'm meaning to first erode the original coloured image in order to supress the black outline. Then next extracting color pixels and in the image2 after reading it i'm trying to subtract it with img1 the residual would be the colored outline, but this code is not working gives mte this error:
---------------------------------------------------------------------------
error Traceback (most recent call last)
/tmp/ipykernel_33/3647166721.py in <module>
43 print(v, v1)
44 img_out = cv2.imread(v1, cv2.IMREAD_UNCHANGED)
---> 45 subtracted = cv2.subtract(img_out, img_erode)
46 # if img_out.shape[2] == 4:
47 # a1 = ~img_out[:,:,3]
error: OpenCV(4.5.4) /tmp/pip-req-build-jpmv6t9_/opencv/modules/core/src/arithm.cpp:647: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'arithm_op'
another approach was to directly pick color pixels from image1 and directly transfer it to second image but as you can see the image has 3 parts with different colors and so its not happening code:
os.chdir('/kaggle/input/maskedoutput')
stroke_list = natsorted(os.listdir())
for i,v in enumerate(stroke_list):
image = cv2.imread(v, cv2.IMREAD_UNCHANGED)
if image.shape[2] == 4:
a1 = ~image[:,:,3]
image = cv2.add(cv2.merge([a1,a1,a1,a1]), image)
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
else:
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
plt.imshow((image))
plt.show()
copy = image.copy()
kernel = np.ones((15,15), np.uint8)
closing = cv2.morphologyEx(copy, cv2.MORPH_CLOSE, kernel)
img_erode = cv2.erode(closing, kernel, iterations=1)# to supress black outline
height, width, channel = img_erode.shape
for x1 in range(0,width):
for y1 in range(0,height):
channels_x1y1 = img_erode[y1,x1]
os.chdir('/kaggle/input/maskstrokes')
output = natsorted(os.listdir())
for idx,v1 in enumerate(output):
if(v==v1):
print(v, v1)
img_out = cv2.imread(v1, cv2.IMREAD_UNCHANGED)
height2, width2, channel2 = img_out.shape
for x1 in range(0,width2):
for y1 in range(0,height2):
channels_x1y1 = img_out[y1,x1]
else:
continue
plt.imshow(cv2.cvtColor(img_out, cv2.COLOR_BGR2RGB))
plt.show()
Upvotes: 1
Views: 2284
Reputation: 21203
I prepared a quick fix solution based on the expected output.
I used the following image as input:
Code:
img = cv2.imread('colored_objects.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# binary mask
mask = cv2.threshold(gray,10,255,cv2.THRESH_BINARY)[1]
# inverted binary mask
th = cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)[1]
# finding external contours based on inverted binary mask
contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# create copy of original image to draw contours
img2 = img.copy()
In the following, we iterate through each contour. For each contour:
centroid
)color
)img2
)code:
for c in contours:
M = cv2.moments(c)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
centroid = (cx, cy)
color = tuple(img[cy, cx])
color = ( int (color [ 0 ]), int (color [ 1 ]), int (color [ 2 ]))
print(color)
img2 = cv2.drawContours(img2, [c], 0, tuple(color), -1)
Now we subtract the original from the newly drawn image r
. Based on mask
, wherever pixels are white we assign white in r
r = img2 - img
r[mask == 255] = (255, 255, 255)
Update:
Expected result for the latest image. The green shade is present on the border as expected. This was obtained using the same code without any changes:
Upvotes: 2