0

I'm trying to create a program to threshold different colours and in the program I have a function for going back to the last colour range, but every time I tried to add new values to the lists(minse, maxse) that hold these old values then all the lists for that particular colour in the list turn to the new appended list.

import cv2
import numpy as np
import cPickle as pickle
from matplotlib import pyplot as plt

def nothing(x):
    pass

cap = cv2.VideoCapture(0)
cv2.namedWindow('image')
#last values
minse = [[],[],[]]
maxse = [[],[],[]]
p = 0
try:
    mins, maxs= pickle.load(open("varvid.p", "rb"))
except:
    mins = np.array([[255,255,255],[255,255,255],[255,255,255]])
    maxs = np.array([[0,0,0],[0,0,0],[0,0,0]])


cv2.createTrackbar('brush_size','image',1,10, nothing)
cv2.createTrackbar('vahe','image',0,50, nothing)


# mouse callback function
def choose_color(event,x,y,flags,param):
    global mins, maxs, minse, maxse, p, brush_size, vahe

    if event == cv2.EVENT_LBUTTONDOWN:
        nx = brush_size
        ny = brush_size
        pixs = hsv[y-ny:y+ny,x-nx:x+nx,:] 
        print minse[p]
        print mins[p]
        minse[p].append(mins[p])
        print minse[p]
        maxse[p].append(maxs[p])
        mins[p]=np.minimum(mins[p], pixs.min(0).min(0) - vahe).clip(0, 255).astype('uint8')
        print mins[p]
        maxs[p]=np.maximum(maxs[p], pixs.max(0).max(0) + vahe).clip(0, 255).astype('uint8')

#deletes lasts maxs and mins
def eelmised_varvid():
    global maxs, maxse, mins, minse, p
    try:    

        maxs[p] = maxse[p].pop()
        mins[p] = minse[p].pop()

    except:
        mins[p] = np.array([255,255,255])
        maxs[p] = np.array([0,0,0])

cv2.namedWindow('tava')
cv2.setMouseCallback('tava', choose_color)

print("For exiting press 'q', to save the values 's', ball colors - 'p', yellow - 'y' and blue -  'b', default is  the ball")

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV) 
    brush_size =cv2.getTrackbarPos('brush_size','image')
    vahe = cv2.getTrackbarPos('brush_size','image')

    # Display the resulting frame
    median = cv2.medianBlur(hsv,5)
    mask = cv2.inRange(hsv, mins[p], maxs[p])


    cv2.imshow('tava', median)
    cv2.imshow('mask', mask)
    k = cv2.waitKey(1) & 0xFF

    if k == ord('q'):
        break
    elif k == ord('p'):
        p = 0
    elif k == ord('y'):
        p = 1
    elif k == ord('b'):
        p = 2
    elif k == ord('s'):
        pickle.dump([mins,maxs], open("varvid.p", "wb"))
    elif k == ord('e'):
        eelmised_varvid()
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

The problem should be in this part of the code:

def choose_color(event,x,y,flags,param):
    global mins, maxs, minse, maxse, p, brush_size, vahe

    if event == cv2.EVENT_LBUTTONDOWN:
        nx = brush_size
        ny = brush_size
        pixs = hsv[y-ny:y+ny,x-nx:x+nx,:]
        print"The value that should be appended to the old value list:",mins[p]
        print"The old value list before appending:", minse[p]
        minse[p].append(mins[p])
        print"The old value list after appending:",minse[p]
        maxse[p].append(maxs[p])
        mins[p]=np.minimum(mins[p], pixs.min(0).min(0) - vahe).clip(0, 255).astype('uint8')
        maxs[p]=np.maximum(maxs[p], pixs.max(0).max(0) + vahe).clip(0, 255).astype('uint8')

and an example: first click: The value that should be appended to the old value list: [255 255 255] The old value list before appending: [] The old value list after appending: [array([255, 255, 255])] and a second click: The value that should be appended to the old value list: [ 84 33 237] The old value list before appending: [array([ 84, 33, 237])] The old value list after appending: [array([ 84, 33, 237]), array([ 84, 33, 237])]

EDIT: well I tried to debug it some more and found out that it's not the .append() functions problem, but for some reason this line of code:

mins[p]=np.minimum(mins[p], pixs.min(0).min(0) - vahe).clip(0, 255).astype('uint8')

changes the value of minse[p]

Any help would be appriciated and thanks in advance :)

Joss
  • 3
  • 2
  • 3
    You should try to narrow the code to the related area, Also try to give an example (with actual values) it will help us to understand your question. – Kobi K Oct 02 '14 at 07:54
  • What is the question? according to the example, the append is working fine since it's appending. what do you expect to happen? – Kobi K Oct 02 '14 at 08:14
  • The problem is that it's not only appending but it also changes the lists in the list to the list that I am appending to the list or somehow the values of the old value list change, but I don't know how – Joss Oct 02 '14 at 08:15

1 Answers1

1

The thing is, a Python list doesn't really store "data", it just stores references to other objects. Your problem can be reduced:

list_ = []
thing = [0, 0]
list_.append(thing)
print list_
# [[0, 0]]

thing[0] = 1
list_.append(thing)
print list_
# [[1, 0], [1, 0]]

So when you do the above, you end up with a list like [thing, thing]. The momentary content of thing decides what is shown as the content of list_.

Also, notice that when you now do:

thing = [2, 2]
list_.append(thing)
print list_
# [[1, 0], [1, 0], [2, 2]]

The old content of the list didn't change, because you didn't change thing, or rather, the object referenced to by the label "thing". Instead you assigned a new object to the label "thing" and this doesn't mess with the objects previously attached to that label.

This behavior is only a concern when the content put in the list (or other collection type) is a "mutable" object, like e.g. list, dict, or a Numpy array. For more info see e.g. this question.

The solution: make copies of the objects you put in the list. In your case:

minse[p].append(mins[p].copy())
Community
  • 1
  • 1