img = cv2.imread('mandrill.png')
histg = cv2.calcHist([img],[0],None,[256],[0,256])
if len (sys.argv) < 2:
print >>sys.stderr, "Usage:", sys.argv[0], "<image>..."
sys.exit (1)
for fn in sys.argv[1:]:
im = cv2.imread (fn)
histr = cv2.calcHist([im],[0],None,[256],[0,256])
a = cv2.compareHist(histr,histg,cv2.cv.CV_COMP_CORREL)
print a
I am trying to use the code above to compare the correlation between histograms histr and histg when I run the code the I get the error
'module' object has no attribute 'cv'
It seems that CV3 the names of the various correlation functions have changed. What are the names of the various correlation functions?
The opencv version you are using has cv2.cv.CV_COMP_CORREL renamed to cv2.HISTCMP_CORREL
The function name changes are as follows (left hand side shows the names for opencv2, right hand side shows the name for the latest version of opencv(opencv3)):
cv2.cv.CV_COMP_CORREL:: cv2.HISTCMP_CORREL
cv2.cv.CV_COMP_CHISQR :: cv2.HISTCMP_CHISQR/ cv2.HISTCMP_CHISQR_ALT
cv2.cv.CV_COMP_INTERSECT :: cv2.HISTCMP_INTERSECT
cv2.cv.CV_COMP_BHATTACHARYYA :: cv2.HISTCMP_BHATTACHARYYA
As Zdar mentioned it looks like the constants have been renamed in opencv3.0 to:
cv2.HISTCMP_CORREL
cv2.HISTCMP_CHISQR
cv2.HISTCMP_INTERSECT
cv2.HISTCMP_BHATTACHARYYA
a = cv2.compareHist(histr,histg,cv2.HISTCMP_CORREL) should work
sample code for compare histogram in OpenCV 3.2
import cv2
path='location_of_images'
im1 = cv2.imread(path+'/'+'first.jpg',0)
hist1 = cv2.calcHist([im1],[0],None,[256],[0,256])
im2 = cv2.imread(path+'/'+'second.jpg',0)
hist2 = cv2.calcHist([im2],[0],None,[256],[0,256])
a=cv2.compareHist(hist1,hist2,cv2.HISTCMP_BHATTACHARYYA)
print a
return value show how close to your test image with compared one.
example: cv2.HISTCMP_BHATTACHARYYA method gives zero(0.0) for the same image.
other methods are cv2.HISTCMP_CHISQR,cv2.HISTCMP_CHISQR_ALT,cv2.HISTCMP_CORREL cv2.HISTCMP_HELLINGER,cv2.HISTCMP_INTERSECT,cv2.HISTCMP_KL_DIV.
Related
So I am trying to make a painterly node group with Python code straight so I can use it for future projects but I can't seem to get the power part of the formula in nuke to work from this colour difference formula( I'm also new to Nuke so if there is a better way of writing this please let me know it would be awesome thank you, or if I'm doing this wrong completely also let me know)
The following formula for color difference is used to create the
difference image: |(r1,g1,b1) – (r2,g2,b2)| = ((r1 – r2)^2 + (g1
–g2)^2 + (b1 – b2)^2)^1/2.
nRedShuffle = nuke.nodes.Shuffle()
nRedShuffle['red'].setValue('red')
nRedShuffle['green'].setValue('red')
nRedShuffle['blue'].setValue('red')
nRedShuffle['alpha'].setValue('red')
nGreenShuffle = nuke.nodes.Shuffle()
nGreenShuffle['red'].setValue('green')
nGreenShuffle['green'].setValue('green')
nGreenShuffle['blue'].setValue('green')
nGreenShuffle['alpha'].setValue('green')
#...(so on for the rest of rgba1 and rgba2)
nGreenShuffle2 = nuke.nodes.Shuffle()
nGreenShuffle2['red'].setValue('green')
nGreenShuffle2['green'].setValue('green')
nGreenShuffle2['blue'].setValue('green')
nGreenShuffle2['alpha'].setValue('green')
nBlueShuffle2 = nuke.nodes.Shuffle()
nBlueShuffle2['red'].setValue('blue')
nBlueShuffle2['green'].setValue('blue')
nBlueShuffle2['blue'].setValue('blue')
nBlueShuffle2['alpha'].setValue('blue')
#I am having troubles with the powers below
redDiff = nuke.nodes.Merge2(operation='minus', inputs=[nRedShuffle2, nRedShuffle])
redDiffMuli = nuke.nodes.Merge2(operation='multiply', inputs=[redDiff, redDiff])
greenDiff = nuke.nodes.Merge2(operation='minus', inputs=[nGreenShuffle2, nGreenShuffle])
greenDiffMuli = nuke.nodes.Merge2(operation='multiply', inputs=[greenDiff, greenDiff])
blueDiff = nuke.nodes.Merge2(operation='minus', inputs=[nBlueShuffle2, nBlueShuffle])
blueDiffMuli = nuke.nodes.Merge2(operation='multiply', inputs=[blueDiff, blueDiff])
redGreenAdd = nuke.nodes.Merge2(operation='plus', inputs=[redDiffMuli, greenDiffMuli])
redGreenBlueAdd = nuke.nodes.Merge2(operation='plus', inputs=[redGreenAdd, blueDiffMuli])
Here are at least two ways to implement Color Difference formula for two images. You can use difference op in Merge node or you can write a formula in field for each channel inside MergeExpression node:
Expression for each channel is as simple as this:
abs(Ar-Br)
abs(Ag-Bg)
abs(Ab-Bb)
Python commands
You can use .nodes.MergeExpression methodology:
import nuke
merge = nuke.nodes.MergeExpression(expr0='abs(Ar-Br)',
expr1='abs(Ag-Bg)',
expr2='abs(Ab-Bb)')
or regular .createNode syntax:
merge = nuke.createNode('MergeExpression')
merge['expr0'].setValue('abs(Ar-Br)')
merge['expr1'].setValue('abs(Ag-Bg)')
merge['expr2'].setValue('abs(Ab-Bb)')
Full code version
import nuke
import nukescripts
red = nuke.createNode("Constant")
red['color'].setValue([1,0,0,1])
merge = nuke.createNode('MergeExpression')
merge['expr0'].setValue('abs(Ar-Br)')
merge['expr1'].setValue('abs(Ag-Bg)')
merge['expr2'].setValue('abs(Ab-Bb)')
yellow = nuke.createNode("Constant")
yellow['color'].setValue([1,1,0,1])
merge.connectInput(0, yellow)
nuke.toNode('MergeExpression1').setSelected(True)
nukescripts.connect_selected_to_viewer(0)
# Auto-alignment in Node Graph
for everyNode in nuke.allNodes():
everyNode.autoplace()
Consider! MergeExpression node is much slower that regular Merge(difference) node.
I have to test out a code in Pycharm (the bottom of the question), but I cannot figure out how to run it in Pycharm without getting this error:
usage: color.py [-h] -i IMAGE
color.py: error: the following arguments are required: -i/--image
I know that if I was using Idle I would have written this code:
/Users/syedrishad/Downloads/python-project-color-detection/color_detection.py -i
Users/syedrishad/Downloads/python-project-color-detection/colorpic.jpg
But I don't know how to run it on Pycharm
I use a mac and for some reason i always have to put the full path name or it doesn't work.(If that makes a difference)
This program makes it so if I double click on a part of the image, it shows the exact color name. All the color names are stored in this file:
/Users/syedrishad/Downloads/python-project-color-detection/colors.csv
The actual code is here:
import cv2
import numpy as np
import pandas as pd
import argparse
#Creating argument parser to take image path from command line
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--image', required=True, help="Image Path")
args = vars(ap.parse_args())
img_path = args['image']
#Reading the image with opencv
img = cv2.imread(img_path)
#declaring global variables (are used later on)
clicked = False
r = g = b = xpos = ypos = 0
#Reading csv file with pandas and giving names to each column
index=["color","color_name","hex","R","G","B"]
csv = pd.read_csv('colors.csv', names=index, header=None)
#function to calculate minimum distance from all colors and get the most matching color
def getColorName(R,G,B):
minimum = 10000
for i in range(len(csv)):
d = abs(R- int(csv.loc[i,"R"])) + abs(G- int(csv.loc[i,"G"]))+ abs(B- int(csv.loc[i,"B"]))
if(d<=minimum):
minimum = d
cname = csv.loc[i,"color_name"]
return cname
#function to get x,y coordinates of mouse double click
def draw_function(event, x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
global b,g,r,xpos,ypos, clicked
clicked = True
xpos = x
ypos = y
b,g,r = img[y,x]
b = int(b)
g = int(g)
r = int(r)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_function)
while(1):
cv2.imshow("image",img)
if (clicked):
#cv2.rectangle(image, startpoint, endpoint, color, thickness)-1 fills entire rectangle
cv2.rectangle(img,(20,20), (750,60), (b,g,r), -1)
#Creating text string to display( Color name and RGB values )
text = getColorName(r,g,b) + ' R='+ str(r) + ' G='+ str(g) + ' B='+ str(b)
#cv2.putText(img,text,start,font(0-7),fontScale,color,thickness,lineType )
cv2.putText(img, text,(50,50),2,0.8,(255,255,255),2,cv2.LINE_AA)
#For very light colours we will display text in black colour
if(r+g+b>=600):
cv2.putText(img, text,(50,50),2,0.8,(0,0,0),2,cv2.LINE_AA)
clicked=False
#Break the loop when user hits 'esc' key
if cv2.waitKey(20) & 0xFF ==27:
break
cv2.destroyAllWindows()
If you know how to run, can you please tell me. I have been searching for an answer but come up empty-handed.
As #Yves Daoust mentioned you basically have two options:
A) Either change the code you are testing to provide the required argument or
B) Use Run->Run...->Edit Configurations... to provide the argument as you would from the command line.
Let's examine in more details the options you have:
A) The easiest way would be to provide the path to the image you want to open like this:
# replace img_path = args['image'] with
img_path = 'path/to/the/image'
which has the advantage of being extremely easy to get but it breaks the argparser functionality.
A more versatile solution would be to provide a default parameter and edit this one each time you want to open an image.
import argparse
# Add a global variable here. It will provide the argument if no other is given (via `Run->Run...->Edit Configurations...`)
IMAGE_PATH = 'path/to/image'
#Creating argument parser to take image path from command line
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--image', required=True, help="Image Path", default=IMAGE_PATH)
which has the advantage of keeping the arg parse functionality intact if you are interested in this one.
B) This option means you provide the parameters yourself just like you would do in the console. The parameters are put in the Parameters: field.
For example you could pass:
--image="path/to/image"
PyCharm provides the option to Apply (button) the changes you inserted (which in this case would mean to keep the parameters stored for this script as long as the script will be in the memory).
Hope this clarify things a bit.
You have to go to Run > Run and then select the program you want to run. If it still gives an error, check the file path, otherwise, you have an error in your code. I hope that answers your question.
I found out that the .size.height and .size.width operators of OpenCV's RotatedRect class don't work in Python whereas they work in C++. Let me elaborate with a simplified code snippet:
cap = cv2.VideoCapture('video1.mp4')
filter = RandomClass(20)
while(cap.isOpened()):
ret, frame = cap.read() # Read a frame
res = filter.classMain(frame) # Process the frame
if (res == 0):
print('Success') # If processing completed, print Success
cap.release()
where the class definition is as follows:
import cv2
import numpy as np
class RandomClass:
def __inti__(self):
self.set_skip_first(True)
def get_skip_first(self):
return self.skip_first
def set_skip_first(self, value):
self.skip_first = value
def classMain(self, frame):
if not get_skip_first():
self.expand_minRect(100) # expand the minRect by 100 pixels
# use the expanded rectangle for some other processing here
else:
self.set_skip_first(False)
# create a mask with cv2.inRange
contour = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE, offset=(0,0))[1]
# iterate over each contour and find the index of the largest contour
self.minRect = cv2.minAreaRect(np.array(self.contours[self.largest_contour_index]))
# execute some other processing here
return 0
def expand_minRect(self, value):
self.minRect.size.height = self.minRect.size.height + value
self.minRect.size.width = self.minRect.size.width + value
The error I'm receiving is as follows. The exact lines work perfectly fine in the C++ version of the above code.
File "filename", line 106, in expand_minRect
self.minRect.size.height = self.minRect.size.height + value
AttributeError: 'tuple' object has no attribute 'size'
I tried the following. I was expecting the second printed value (of variable width2) to be greater than the first printed value (of variable width1) by value.
def expand_minRect(self, value):
_,(width1, height1),_ = self.minRect
print(width)
self.minRect[1][0] = self.minRect[1][0] + value
_,(width2,height2),_ = self.minRect
print(w)
However it didn't work as the variable type of self.minRect[1][0] is Tuple and Tuples cannot be modified.
File "filename", line 111, in expand_minRect
self.minRect1[0] = self.minRect1[0] + value
TypeError: 'tuple' object does not support item assignment
I did some research, I couldn't find a Python documentation for RotatedRect but I found a stackoverflow answer stating that
Python still lacks of RotatedRect class
So all things to a side, assuming that the RotatedRect support in Python3 is incomplete, how can I work around this and expand the width and height of my minRect variable?
According to this tutorial, minAreaRect returns a rectangle with ((center_x,center_y),(width,height),angle). Thus, if you modify your expand_minRect to recreate it with the correct components, it should work.
def expand_minRect(self, value):
self.minRect = (self.minRect[0], # keep the center
(self.minRect[1][0] + value, self.minRect[1][1] + value), # update the size
self.minRect[2]) # keep the angle
Note: The problem emerges from the fact that OpenCV python has a less object-oriented implementation than OpenCV c++. It does not return a struct which enables accessing each attribute by name (like ".size"). You need to know the tuple order and assumptions for each element.
please bear with me - I'm new to all this. I tried the searches and have only found bits and pieces to what I'm looking for, but not what I need to connect them.
Basically, I'm trying to create a Python script that allows the user to simply "0" out multiple selected attributes on Maya's Channel box.
So far I have:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
print selObjs # returns [u'pCube1']
print selAttrs # returns [u'ty']
If I would like to set the attributes:
cmds.setAttr(selObjs + "." + selAttrs, '0')
of course this is wrong, so how do I properly execute the setAttr command in this sceneario? (The intention includes having to set them if I have multiple selected attributes in the channel box).
I found that in MEL, it works like this. So really I just need help figuring out how to create the python counterpart of this:
string $object[] = `ls -sl`;
string $attribute[] = `channelBox -q -sma mainChannelBox`;
for ($item in $object)
for($attr in $attribute)
setAttr ($item + "." + $attr) 0;
Moving after that, I need an if loop where, if the attribute selected is a scale attribute, the value should be 1 - but this is something I'll look into later, but wouldn't mind being advised on.
Thanks!
So here's what I finally came up with:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
scales = ['sy','sx','sz','v']
if not selObjs:
print "no object and attribute is selected!"
elif not selAttrs:
print "no attribute is selected!"
else:
for eachObj in selObjs:
for eachAttr in selAttrs:
if any(scaleVizItem in eachAttr for scaleVizItem in scales):
cmds.setAttr (eachObj+"."+eachAttr, 1)
else:
cmds.setAttr (eachObj+"."+eachAttr, 0)
This will reset the basic transformations to their defaults. Including an if for the scale and visibility values.
I managed to come up with this:
import maya.cmds as cmds
selObjs = cmds.ls(sl=1)
selAttrs = cmds.channelBox("mainChannelBox", q=1, sma=1)
for each in selObjs:
for eachAttr in selAttrs:
cmds.setAttr (each+"."+eachAttr, 0)
And It's working to zero out selected attributes perfectly.
Now im at the stage of figuring out how to get the script to recognize if it contains scale attributes - to change that value to 1 instead of 0. (stuck at how to extract values from a list at the moment)
I have 4 directories with images for an animation. I would like to take the set of images and generate a single image with the 4 images arranged into a 2x2 grid for each frame of the animation.
My code so far is:
import Image
fluid64 = "Fluid64_half_size/00"
fluid128 = "Fluid128_half_size/00"
fluid512 = "Fluid512_half_size/00"
fluid1024 = "Fluid1024_half_size/00"
out_image = "Fluid_all/00"
for pic in range(1, 26):
blank_image = Image.open("blank.jpg")
if pic < 10:
image_num = "0"+str(pic)
else:
image_num = str(pic)
image64 = Image.open(fluid64+image_num+".jpg")
image128 = Image.open(fluid128+image_num+".jpg")
image512 = Image.open(fluid512+image_num+".jpg")
image1024 = Image.open(fluid1024+image_num+".jpg")
out = out_image + image_num + ".jpg"
blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (0,300)).paste(fluid1024, (400,300)).save(out)
Not sure why it's not working. I'm getting the error:
Traceback (most recent call last):
File "C:\Users\Casey\Desktop\Image_composite.py", line 24, in <module>
blank_image.paste(image64, (0,0)).paste(fluid128, (400,0)).paste(fluid512, (
ste(fluid1024, (400,300)).save(out)
AttributeError: 'NoneType' object has no attribute 'paste'
shell returned 1
Any help would be awesome. Thanks!
The only problem there is that "paste" does not return an image object - it rather modifies the "blank" image inplace.
So, when the second paste is called (the one that uses the fuild128 image), it tries to be applied on "None" - which is the return value of the first image.
If that is the only problem you are having, just make one paste call per line, like this:
blank_image.paste(image64, (0,0))
blank_image.paste(fluid128, (400,0))
blank_image.paste(fluid512, (0,300))
blank_image.paste(fluid1024, (400,300))
blank_image.save(out)
Although it looks likely you'd need to scale each image so that their format match as well.
And your code for the "image_num" variable is unecessary. Python is really good with strings - just do something like this:
image64 = Image.open(fluid64 + "%02d.jpg" % pic)
You may want to be using something along the lines of :
blank_image = Image.new("RGB", (800, 600))
This will create a new area in memory in which you can generate your image. You should then be able to paste you images into that.
Then you'll need to save it out again later on with:
blank_image.save("blank.jpg")
Read the error message:
AttributeError: 'NoneType' object has no attribute 'paste'
This means you tried to call .paste on something that was of type NoneType, i.e. on the None object.
Image.paste returns None. You can't "chain" together calls like that except when the functions are specifically designed to support it, and Image.paste is not. (Support for this sort of thing is accomplished by having the function return self. You get an error that talks about NoneType because the function is written not to return anything, and everything in Python returns None by default if nothing else is returned explicitly.) This is considered Pythonic: methods either return a new value, or modify self and return None. Thus, so-called "fluent interfaces" are not used when the functions have side effects - Pythonistas consider that harmful. Returning None is a warning that the function has side effects. :)
Just do four separate .paste calls.
Tiling figures in a 2-by-2 grid would be easy to achieve with the append_images function defined in this reply
https://stackoverflow.com/a/46623632/8738113
For example:
img1 = append_images([image64, image128], direction='horizontal')
img2 = append_images([image512, image1024], direction='horizontal')
final = append_images([img1, img2], direction='vertical')
final.save("Fluid_all/00.jpg")
Unlike PIL APIs copy, crop, resize or rotate which return an Image object, paste returns None which prevents chained method calls. Not so convenient API design.