Python - Local variable referenced before assignment error - python

I am trying to adopt mask_rcnn original code to my dataset.The original code takes xml files and I just modified my code to accept json format. Here is the code
def load_mask(self, image_id, xml=False):
# get details of image
info = self.image_info[image_id]
if xml:
# define anntation file location
path = info['annotation']
# load XML
boxes, w, h = self.extract_boxes(path, xml=True)
else:
with open('D:\Mask_RCNN\Mask_RCNN\dataset\\annots\\annotations.json', 'r') as f:
annots = json.load(f)
found = False
for value in annots.values():
if 'image' in value and value['instance_list']:
if value['image']['original_filename'][:-3] == info['id']:
boxes, w, h = self.extract_boxes(value)
found = True
break
if found:
# create one array for all masks, each on a different channel
masks = zeros([h, w, len(boxes)], dtype='uint8')
else:
stop = "here"
if found:
# create one array for all masks, each on a different channel
masks = zeros([h, w, len(boxes)], dtype='uint8')
else:
stop = "here"
# create masks
class_ids = list()
for i in range(len(boxes)):
box = boxes[i]
row_s, row_e = box[1], box[3]
col_s, col_e = box[0], box[2]
masks[row_s:row_e, col_s:col_e, i] = 1
class_ids.append(self.class_names.index('Penquins'))
return masks, asarray(class_ids, dtype='int32')
# load an image reference
#"""Return the path of the image."""
def image_reference(self, image_id):
info = self.image_info[image_id]
print(info)
return info['path']
It gives me the error
File "C:/PycharmProjects/Mask_RCNN/Mask_RCNN/objects.py", line 197, in load_mask
for i in range(len(boxes)):
UnboundLocalError: local variable 'boxes' referenced before assignment
I tried to debug the code,its throwing an error before creating masks but I am not able to figure out whats wrong. Any idea?

Only if xml is true, it is guaranteed, that boxes gets a value. Otherwise additional conditions have to be fulfilled, which does not seem to be the case.

boxes is initialized in some of the scenarios in load_mask's first if else block, which means it might not exists when you reach if found:. Just declare it in the beginning
def load_mask(self, image_id, xml=False):
# get details of image
info = self.image_info[image_id]
boxes = []

It means that you are trying to iterate over the number of boxes, but your if statements above are constructed in such a way that boxes might not exit by the time this statement gets executed.
try this simple example:
user_input = "no"
if user_input =="yes":
boxes = [1,2,3,4]
else:
pass
print(boxes)
This will result in the same error as you are seeing. Your problem is that both of these if statements must pass before boxes is defined:
if 'image' in value and value['instance_list']:
if value['image']['original_filename'][:-3] == info['id']:
Likely you either need additional logic that ensures the iteration only occurs if certain conditions are met. Or, if boxes is a list you could start your code by defining boxes=[]. In that case the iteration will simply pass over without doing anything as the length of boxes is zero in that case

The problem is that boxes isnt getting declared in line of this for loop, so define boxes as an empty list in the first part of the function
def load_mask(self, image_id, xml=False):
boxes = []
#do all the other stuff here
Then when you do the for loop it should now be declared (unless one of the functions don't return the boxes and give you something else)
Quick tip when doing the for loop, you can do
for i, box in enumerate(boxes):
...
which will not make you define box inside the loop (i will be 0 to len(boxes)-1 and box will be the box with that index)

Related

error in user input for list comprehension

I have an image set which needs to be cropped. I tried implementing different methods to achieve this using user input to specify the pixel range but, none of the methods works. I need to use user input or something similar because the crop sizes is different for other image list and it becomes messy to change code every time.
e.g. of required pixel range [524:1024,275:775]
images = np.array([(plt.imread(fname)) for fname in imglist]).astype(np.int32)
#crop the images
images_crp =np.array([i [input()] for i in images]) # I give input as 524:1024,275:775
#method 2
images_crp = np.array([input() for _ in images]) # I give input as i[524:1024,275:775]
#method 3
images_crp = np.array(i [input():input(),input():input()] for i in images]) # I give input as 524 press enter 1024...
Help is appreciated
Thanks

open each image from a list of images (python)

Very similar questions out already but I haven't been able to find one that really matches what I have going on.
This is a facial recognition app with about 200 lines of code so I will just post the part that is relevant.
The app does face recognition and then displays a the target photo next to the best matched mugshot. In case of false positives it also shows a list of the best 5 matches.
I would like for the images in this list to open upon running the code, however only one image in the list is opening for whatever reason.
Relevant piece of code:
# set distance between known faces and target face. The lower the distance between them the lower the match. Higher dist = more error.
if face_distances[best_match_index] < 0.60:
name = known_face_names[best_match_index]
resulttolog = "Match found within default tolerance level. " + "\n" "Match identified as: " + name + "\n"
log(resulttolog) # logging result
# save and display mugshot of best match
mugshot = cv2.imread(os.getcwd() + "/datasets/" + name + ".jpg")
mugshotresized = cv2.resize(mugshot, (500, 500), fx=0.5, fy=0.5)
cv2.imwrite(os.getcwd() + "/mugshot.jpg", mugshotresized)
# listing other closest maches
best_5_matches = n_known_face_names[top_3_matches]
matchestolist = list(best_5_matches)
log("Best matches in order:")
# sort list by number
for index, mugshot in enumerate(matchestolist, 1):
log("{}. {}".format(index, mugshot)) # log the numbered list
# pop up relevant matches
for filename in matchestolist:
path = os.getcwd() + "/datasets/"
file = path + filename + ".jpg"
img = cv2.imread(file)
cv2.imshow("image", img)
So in this last part, the images are supposed to all open. (i assume one pop up window for each image since its a for loop, but only one window is popping up with the first image).
Seems like an easy solution but I cant figure it out..
Any ideas?
You seem to be showing all images without waiting in the same named window 'image'.
Try
cv2.imshow(filename, img)
so they're opened in different windows?

I keep hitting maximum recursion depth in python. can't figure out a solution

I'm trying to generate about 6000 random images using python's pillow library. Right now I can't create more than 300 at a time or my program hits the maximum recursion depth. I understand that this is happening because my recursion isn't called with an "n-1" case. Being that all the images are selected using random numbers, I'm not sure how to address this issue. Here is my code:
## Generate Traits
TOTAL_IMAGES = 300 # Number of random unique images we want to generate
all_images = []
# A recursive function to generate unique image combinations
def create_new_image():
new_image = {}
# For each trait category, select a random trait based on the weightings
new_image ["Plant"] = random.choices(plant, plant_weights)[0]
new_image ["Pot"] = random.choices(pot, pot_weights)[0]
new_image ["Face"] = random.choices(face, face_weights)[0]
if new_image in all_images:
return create_new_image()
else:
return new_image
# Generate the unique combinations based on trait weightings
for i in range(TOTAL_IMAGES):
new_trait_image = create_new_image()
all_images.append(new_trait_image)
Perhaps you could just use a while True: loop to replace the recursion:
def create_new_image():
while True:
new_image = {}
# For each trait category, select a random trait based on the weightings
new_image ["Plant"] = random.choices(plant, plant_weights)[0]
new_image ["Pot"] = random.choices(pot, pot_weights)[0]
new_image ["Face"] = random.choices(face, face_weights)[0]
if new_image not in all_images:
return new_image
I found the error in my thinking. The recursion DOES work as it should. Because I only had 7^3 possibilities at the moment (due to not having the other attributes finished) my recursion was simply maxing out needlessly. Once I included the future attributes my program had no issue cranking out 6000 unique possibilities because there are 7^8 to choose from.
Thanks to #chepner for the tip off in the comments

Python-pptx formatting datalabels after adding text

As I needed to add custom text to a chart data labels in python-pptx I used
for point in plot.series[1].points:
frame = point.data_label.text_frame
frame.text = "Test "
for run in frame.paragraphs[0].runs:
run.font.size = Pt(10)
run.font.color.rgb = RGBColor(0x0A, 0x42, 0x80)
This allowed me to change the font to the labels but I would need to rotate them.
I saw the solution from This other thread but it does not work. Any ideas?
I believe you need to change the txPr (as in the thread you mention) but on the respective element child:
for all_series in range(0, len(plot.series)):
for i in range(0, len(plot.series[all_series]._element)):
if re.sub("{.*}", '', plot.series[all_series]._element[i].tag) == >"dLbls":
txPr = plot.series[all_series]._element[i].get_or_add_txPr()
txPr.bodyPr.set('rot', '-5400000')
So you need to access the "dLbls" child within the correct element index, the "[i]" is the difference to the mentioned thread. I use regular expressions to derive the name from the ".tag"-method. There is probably a better way to find the correct index, but this is at least one ;)
This solution iterates over all series, if you do not need this you can skip the first loop (assuming you want only the 1-series):
for i in range(0, len(plot.series[1]._element)):
if re.sub("{.*}", '', plot.series[1]._element[i].tag) == "dLbls":
txPr = plot.series[1]._element[i].get_or_add_txPr()
txPr.bodyPr.set('rot', '-5400000')
Note, that this only applies to data labels which were set on the single point, so e.g. through
plot.series[1].points[0].data_label.text_frame.text = "Foo"
Hopefully this helps :)
You can try this custom function, feed in your plot variable, and other style properties as you needed. If we go at point level for data label then this wont work as we think, and below can help to achieve.
def apply_data_labels(plot,font,fontsize,numformat,rotate = False):
plot.has_data_labels = True
data_labels = plot.data_labels
data_labels.font.size = Pt(fontsize)
data_labels.font.name = font
if rotate == True:
data_labels._element.get_or_add_txPr().bodyPr.set('rot','-5400000')
data_labels.number_format = numformat
and call this function with your plot variable for example.
apply_data_labels(chart.plots[0],'Invention',10,'#,##0;[Red]#,##0',rotate = True)

Drawing 1 image from previous image set + 2 random images from list (Python/Psychopy)

In the code below i am drawing 3 images from a list (targetset) then displaying them to the screen. Next I am displaying another 3 images (pics) to a different part of the screen. For this second part; on 50% of occasions I want the 'pics' images to be the same as those displayed initially (target set). I am ok with this part, I am setting pics = targetset when x == 0 (basically flipping a coin).
My probleme is, on the other 50% of occasions I want one of the 'pics' set to be the same as one of the orignally showed set (targetset), any one of the three. And i want the remaining 2 to be randomly choosen from the pics list. As it stands, according to my logic, I can only get the 'pics' images to be all the same, or all different as the originally shown images from 'targetset'.
Adding to the problem: When x==0 (making pics=targetset) they all display ok, but when x==1 (meaning make no change) i get the following error message:
pics[i].pos = location[i]
UnboundLocalError: local variable 'pics' referenced before assignment
Here is my code:
#create initial target set
imgList1 = glob.glob(os.path.join('stim','*.png'))
random.shuffle(imgList1)
targetset = [visual.ImageStim(window, img) for img in imgList1[:3]]
#initial target set location
setlocation = [(-2,0),(0,0),(2,0)]
random.shuffle(setlocation)
#create target list
imgList = glob.glob(os.path.join('stim', '*.png'))
random.shuffle(imgList)
pics = [visual.ImageStim(window, img) for img in imgList[:3]]
#set target locations
location = [(1,2),(3,3),(5,5)]
random.shuffle(location)
'''define sequential presentation function'''
def seq():
x = random.randint(0,1)
if x == 0:
pics = targetset
print x
#display initial target set
for i in range(3):
targetset[i].pos = setlocation[i]
targetset[i].draw()
window.flip()
core.wait(3)
#display targets
for i in range(3):
pics[i].pos = location[i]
pics[i].draw()
window.flip()
core.wait(1)
seq()
core.wait(3)
window.close()
quit()
I hope someone can help,
Cheers
S
I see a few possible pitfalls with your code. One is that you are creating two separate lists imgList1 and imgList from the same set of images, then you are randomizing each of these lists separately and pulling the first three elements from each list into targetset and pics respectively. It is possible that these sub-sets will have some overlap in images. From the description of your task, I don't think that this is intentional. I might suggest creating only 1 imgList and then using the imgList.pop() function to pull images from the list. Pop returns the last element from the list and then deletes that element from the list. I think of it like drawing a card from a deck, you cannot draw the card again because it is no longer in the deck. What you're currently doing is like drawing cards from two different decks. You might get the same card twice.
The second problem I see here is that you define a condition for what to do when your coin-flip for x is 0, but you do not define one for when your coin-flip is 1. Currently, it will just display the first 3 images from imgList because that's how you've defined pics. I might suggest defining pics within an if/else block for your x coin-flip. If it's 0, then go with targetset, if it's 1, then randomly choose an element from target list, then copy that element to pics and pop two more images from imgList. As with all coding, there is more than one way to solve this problem, but I'll offer a solution here.
#Outside the trial loop
imgList = glob.glob(os.path.join('stim', '*.png'))
random.shuffle(imgList)
#Inside the trial loop
targetset = []
for i in range(0,3):
targetset.append(imgList.pop())
#Do your display stuff with targetset
if random.randint(0,1) == 0:
pics = targetset
else:
pics = []
pics.append(targetset[random.randint(0,2)])
pics.append(imgList.pop())
pics.append(imgList.pop())
random.shuffle(pics)
#Do your display stuff with pics

Categories

Resources