Trying to Plot OpenCV's MSER regions using matplotlib - python

I am using OpenCV's MSER feature detector to find text regions. With the following Python code, I can detect texts (and some non-texts) and draw polygonal curves around each alphabet. Now, I need to plot these texts (more specifically each alphabet) using matplotlib using different colors. Different colors are important here. I am new to matplotlib and I cannot figure out how to implement that. I seek your guidance. I do not need a full solution, but some hints will be helpful.
import numpy as np
import cv2
import matplotlib.pyplot as plt #plt.plot(x,y) plt.show()
img = cv2.imread('TestText.png')
mser = cv2.MSER_create()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
regions = mser.detectRegions(gray, None)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))
# cv2.putText(vis, str('change'), (20, 20), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0))
# cv2.fillPoly(vis, hulls, (0, 255, 0))
# cv2.imwrite("test.png", vis)
cv2.imshow('img', vis)
cv2.waitKey(0)
cv2.destroyAllWindows()

May be, you want the result just like Matlab. You should do more steps to do to get the result. Find the coordinates, modify the values with random color.
Here is my Python 3 code for OpenCV 3.3 .
#!/usr/bin/python3
# 2017.10.05 10:52:58 CST
# 2017.10.05 13:27:18 CST
"""
Text detection with MSER, and fill with random colors for each detection.
"""
import numpy as np
import cv2
## Read image and change the color space
imgname = "handicapSign.jpg"
img = cv2.imread(imgname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
## Get mser, and set parameters
mser = cv2.MSER_create()
mser.setMinArea(100)
mser.setMaxArea(800)
## Do mser detection, get the coodinates and bboxes
coordinates, bboxes = mser.detectRegions(gray)
## Filter the coordinates
vis = img.copy()
coords = []
for coord in coordinates:
bbox = cv2.boundingRect(coord)
x,y,w,h = bbox
if w< 10 or h < 10 or w/h > 5 or h/w > 5:
continue
coords.append(coord)
## colors
colors = [[43, 43, 200], [43, 75, 200], [43, 106, 200], [43, 137, 200], [43, 169, 200], [43, 200, 195], [43, 200, 163], [43, 200, 132], [43, 200, 101], [43, 200, 69], [54, 200, 43], [85, 200, 43], [116, 200, 43], [148, 200, 43], [179, 200, 43], [200, 184, 43], [200, 153, 43], [200, 122, 43], [200, 90, 43], [200, 59, 43], [200, 43, 64], [200, 43, 95], [200, 43, 127], [200, 43, 158], [200, 43, 190], [174, 43, 200], [142, 43, 200], [111, 43, 200], [80, 43, 200], [43, 43, 200]]
## Fill with random colors
np.random.seed(0)
canvas1 = img.copy()
canvas2 = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
canvas3 = np.zeros_like(img)
for cnt in coords:
xx = cnt[:,0]
yy = cnt[:,1]
color = colors[np.random.choice(len(colors))]
canvas1[yy, xx] = color
canvas2[yy, xx] = color
canvas3[yy, xx] = color
## Save
cv2.imwrite("result1.png", canvas1)
cv2.imwrite("result2.png", canvas2)
cv2.imwrite("result3.png", canvas3)
The original image (handicapSign.jpg):
The result:

Related

Change Palette color index in Python

I got this image.
The image is PNG, in mode P, palette is mode RGB.
I need to stay with 16 colors, as I want the image as 4bpp.
And I need to change his palette, making the color pink (255, 192, 203) its first index.
The image palette is:
{(255, 255, 232): 0, (255, 192, 203): 1, (210, 204, 147): 2, (62, 214, 108): 3, (59, 193, 95): 4, (209, 174, 99): 5, (194, 164, 92): 6, (130, 186, 185): 7, (180, 148, 83): 8, (95, 152, 121): 9, (49, 161, 88): 10, (157, 123, 59): 11, (118, 97, 55): 12, (52, 128, 119): 13, (73, 80, 63): 14, (63, 59, 47): 15}
And I want:
{(255, 192, 203): 0, (255, 255, 232): 1, (210, 204, 147): 2, (62, 214, 108): 3, (59, 193, 95): 4, (209, 174, 99): 5, (194, 164, 92): 6, (130, 186, 185): 7, (180, 148, 83): 8, (95, 152, 121): 9, (49, 161, 88): 10, (157, 123, 59): 11, (118, 97, 55): 12, (52, 128, 119): 13, (73, 80, 63): 14, (63, 59, 47): 15}
I made this code for it:
def change_palette(im):
colors = im.palette.colors #get colors from palette
if(PINK not in colors): #check there is pink (could be possible that there is not)
return
first = list(colors.keys())[list(colors.values()).index(0)] #colors is a dict so I get the key of the first index
colors[first] = colors[PINK]
colors[PINK] = 0 #change the value of the colors
newcolors = {}
newcolors[PINK] = colors.pop(PINK)
for key in colors:
newcolors[key] = colors[key] #reorder the dict so it is in order
colors = newcolors
newcolors = []
for key in colors:
for c in key:
newcolors.append(c) #make it a list
im.putpalette(newcolors) #change palette
But it makes the image look like this.
I tried it with other methods, like not using the putpalette and changing only the colors of the palette, but that does not make any change when I save the image.
I understand the problem, but I can't seem to find a solution.
I want it to look exactly the same, but with the color pink (255, 192, 203) in the first index.
If I understand correctly, you want to keep the image unchanged, and replace the index of the pink color to be 0.
When we modify the palette, we are switching between the two colors:
All the pixels with color (255, 255, 232) are switched to pink color (255, 192, 203), and all the pixels with pink color (255, 192, 203) are switched to color (255, 255, 232).
The reason is that the (index) values of the pixels are not changed.
After applying the new palette, all the pixels with (index) value 0 turned to be pink, and all the (index) value 1 turned to be (255, 255, 232).
For fixing that, we have to switch the image data as well (assuming pink color index equals 1):
All the pixels with (index) value 0 should be modified to be value 1.
All the pixels with (index) value 1 should be modified to be value 0.
For convenience we may convert the data to NumPy array, and convert back to PIL Image:
pink_index = colors[PINK] # Original index of pink color
...
indexed = np.array(im) # Convert to NumPy array to easier access.
new_indexed = indexed.copy() # Make a copy of the NumPy array
new_indexed[indexed == 0] = pink_index # Replace all original 0 pixels with pink_index
new_indexed[indexed == pink_index] = 0 # Replace all original pink_index pixels with 0
new_im = Image.fromarray(new_indexed) # Convert from NumPy array to Image.
new_im.putpalette(newcolors) # Set the palette
Complete code sample:
from PIL import Image
import numpy as np
PINK = (255, 192, 203)
def change_palette(im):
colors = im.palette.colors #get colors from palette
if(PINK not in colors): #check there is pink (could be possible that there is not)
return
first = list(colors.keys())[list(colors.values()).index(0)] #colors is a dict so I get the key of the first index
pink_index = colors[PINK]
colors[first] = colors[PINK]
colors[PINK] = 0 #change the value of the colors
newcolors = {}
newcolors[PINK] = colors.pop(PINK)
for key in colors:
newcolors[key] = colors[key] #reorder the dict so it is in order
colors = newcolors
newcolors = []
for key in colors:
for c in key:
newcolors.append(c) #make it a list
#im.putpalette(newcolors) #change palette
indexed = np.array(im) # Convert to NumPy array to easier access https://stackoverflow.com/a/33023875/4926757
new_indexed = indexed.copy() # Make a copy of the NumPy array
new_indexed[indexed == 0] = pink_index # Replace all original 0 pixels with pink_index
new_indexed[indexed == pink_index] = 0 # Replace all original pink_index pixels with 0
new_im = Image.fromarray(new_indexed) # Convert from NumPy array to Image https://stackoverflow.com/a/39258561/4926757
new_im.putpalette(newcolors) # Set the palette
return new_im
img = Image.open('original_image.png')
new_image = change_palette(img)
new_image.save('changed_image.png')
Result:

How to check the accuracy rate of the model trained using hsv color model

I am trying to detect the colour of the images using hsv model.
Below is the code that I have used to detect the colour using hsv model.
import os
import numpy as np
import cv2
# map colour names to HSV ranges
color_list = [
['red', [0, 160, 70], [10, 250, 250]],
['pink', [0, 50, 70], [10, 160, 250]],
['yellow', [15, 50, 70], [30, 250, 250]],
['green', [40, 50, 70], [70, 250, 250]],
['cyan', [80, 50, 70], [90, 250, 250]],
['blue', [100, 50, 70], [130, 250, 250]],
['purple', [140, 50, 70], [160, 250, 250]],
['red', [170, 160, 70], [180, 250, 250]],
['pink', [170, 50, 70], [180, 160, 250]]
]
def detect_main_color(hsv_image, colors):
color_found = 'undefined'
max_count = 0
for color_name, lower_val, upper_val in colors:
# threshold the HSV image - any matching color will show up as white
mask = cv2.inRange(hsv_image, np.array(lower_val), np.array(upper_val))
# count white pixels on mask
count = np.sum(mask)
if count > max_count:
color_found = color_name
max_count = count
return color_found
for root, dirs, files in os.walk('C:/Users/User/Desktop/images/'):
f = os.path.basename(root)
for file in files:
img = cv2.imread(os.path.join(root, file))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print(f"{file}: {detect_main_color(hsv, color_list)}")
The output
image_1 : blue
image_3 : pink
image_12: purple
...
How can I check the accuracy rate of this trained model?
Any help is appreciated.
Thank you.
By eys I think, or test you code on some pure color images.
I think it is better to clarify the definition of "the colour of the image" firstly. For example, what is the color of this image?
you could compare with colorsys
docs.python.org - colorsys
import colorsys
colorsys.rgb_to_hsv(0.2, 0.4, 0.4) = (0.5, 0.5, 0.4)
colorsys.hsv_to_rgb(0.5, 0.5, 0.4) = (0.2, 0.4, 0.4)

how to seprate black curve fromblack texts in opencv with python

import numpy as np
import cv2
im = cv2.imread("goldstandard.png")
nemo = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
hsv_nemo = cv2.cvtColor(nemo, cv2.COLOR_RGB2HSV)
dictionaryHSV = {
"greenCombo": [[30, 126, 87], [70, 255, 250]],
'red': [[0, 92, 212], [10, 265, 255]],
'blue': [[110, 7, 214], [130, 255, 255]],
'black': [[0, 0, 0], [10, 10, 40]],
'another1': [[20, 245, 151], [40, 255, 231]],
'pink': [[140, 126, 215], [160, 146, 255]]
}
for r1, r2 in dictionaryHSV.values():
lower = np.array(r1)
upper = np.array(r2)
mask = cv2.inRange(hsv_nemo, lower, upper)
# cv2.imshow("masked",mask)
# cv2.waitKey(0)
nm = np.ones((nemo.shape[0], nemo.shape[1], nemo.shape[2]), dtype=np.uint8)
for i in range(nm.shape[0]):
for j in range(nm.shape[1]):
nm[i][j] = (255, 255, 255)
result = cv2.bitwise_and(nm, nm, mask=mask)
cv2.imshow("mappped", result)
cv2.waitKey(0)
i have curve plot images and i want to separate all curves based on color i am getting a problem when i come across black curve i get black curve along with black text in the plot i want to only get the curve not the text. I used color ranges in "H.S.V" color-space to recognize colors. Thanks in advance.
Extract region inside square.
Remove all non black pixels.
Find all contours.
Select a biggest contour - it will be your curve.

estimateTransformation in CV2 is difference with document

The document is https://docs.opencv.org/3.0-beta/modules/shape/doc/shape_transformers.html
void estimateTransformation(InputArray transformingShape, InputArray targetShape, std::vector& matches)
So that i run my code
import cv2
import numpy as np
import matplotlib.pyplot as plt
tps = cv2.createThinPlateSplineShapeTransformer()
sshape = np.array ([[67, 90], [206, 90], [67, 228], [206, 227]], np.float32)
tshape = np.array ([[64, 63], [205, 122], [67, 263], [207, 192]], np.float32)
sshape = sshape.reshape (1, -1, 2)
tshape = tshape.reshape (1, -1, 2)
matches = list ()
matches.append (cv2.DMatch (0, 0, 0))
matches.append (cv2.DMatch (1,1,0))
matches.append (cv2.DMatch (2, 2, 0))
matches.append (cv2.DMatch (3, 3, 0))
tps.estimateTransformation (tshape, sshape, matches)
ret, tshape = tps.applyTransformation (sshape)
img = cv2.imread ('tiger.jpg', 1)
out_img = tps.warpImage (img)
plt.imshow(cv2.cvtColor(out_img, cv2.COLOR_BGR2RGB))
plt.show()
cv2.waitKey(0)
cv2.waitKey(0)
The result looks like reverse which i expected
enter image description here
So, i change my code tps.estimateTransformation (tshape, sshape, matches)
And i got expected result.
enter image description here
This is wrong in document or my code is fail.

How can I use warpperspective on separate parts of the same image?

Let's say I have an image of a book cover that I want to "flatten". To do so it seems like I would need to perform 2 perspective transforms: one just for the front cover and one just for the back cover:
What would be the most efficient way to do this?
Using a 600x600 pixel image homograpy-test.jpg:
import cv2
import numpy as np
#load image
img = cv2.imread('homography-test.jpg', cv2.IMREAD_COLOR)
#corners of book covers (before)
frontCoverPtsBefore = np.array([[32, 48], [279, 136], [247, 430], [39, 281]], dtype="float32")
backCoverPtsBefore = np.array([[279, 136], [474, 36], [463, 316], [247, 430]], dtype="float32")
#corners of book covers (after)
frontCoverPtsAfter = np.array([[0, 0], [299, 0], [299, 599], [0, 599]], dtype="float32")
backCoverPtsAfter = np.array([[300, 0], [599, 0], [599, 599], [300, 599]], dtype="float32")
#get the transformation matrices for both covers
M_front = cv2.getPerspectiveTransform(frontCoverPtsBefore, frontCoverPtsAfter)
M_back = cv2.getPerspectiveTransform(backCoverPtsBefore, backCoverPtsAfter)
#warpPerspective both images
img_front = cv2.warpPerspective(img, M_front, (600, 600))
img_back = cv2.warpPerspective(img, M_back, (600, 600))
#copy half of the warped back cover into the warped front cover
np.copyto(img_front[:, 300:, :], img_back[:, 300:, :])
#display before and after
cv2.imshow('img', img)
cv2.imshow('img_front', img_front)
cv2.waitKey(0)
cv2.destroyAllWindows()
Before and After:

Categories

Resources