Open teasey opened 2 years ago
For pictures that seems straightforward. How would it work for video? Does the censor style get randomly chosen each frame?
my first instinct would be: as long as the box has the same item to censor and doesnt move by more than x/y pixel per (newly generated censor) frame it stays the same (if at some point stickers/captions are implemented the same text/sticker maybe?)
this might help with the same object using the same censorstyle
im not sure if i can link it here, but on milovana forum there is a tool called beta.exe which does something like this, sadly its not open source code and supposedly not very secure (as someone in the thread says)
This might be something that comes later. Feature tracking (figuring out if an identified feature is the same identified feature as before) is much harder than feature identification. It is arguably needed for stickers, which I do hope to support, but that's a bit down the line.
i've coded the basic functionality of this (it is very straight forward):
in betaconfig:
#censor style weights
pixel_weight = 550
pixel_censor_style = [ 'pixel', 10 ]
bar_weight = 50
bar_censor_style = [ 'bar', (247,154,192) ]
blur_weight = 50
blur_censor_style = [ 'blur', 50 ]
pixel_weight_calc = pixel_weight / (pixel_weight + bar_weight + blur_weight)
bar_weight_calc = bar_weight / (pixel_weight + bar_weight + blur_weight)
blur_weight_calc = blur_weight / (pixel_weight + bar_weight + blur_weight)
_a new function in betautilsconfig:
def randomize_censor_style():
censor_style_rnd = []
rnd_censor_var = random.uniform(0,1)
if rnd_censor_var < betaconfig.pixel_weight_calc:
censor_style_rnd = betaconfig.pixel_censor_style
if rnd_censor_var > betaconfig.pixel_weight_calc:
censor_style_rnd = betaconfig.bar_censor_style
if rnd_censor_var > betaconfig.pixel_weight_calc + betaconfig.bar_weight_calc:
censor_style_rnd = betaconfig.blur_censor_style
return censor_style_rnd
_and a change to get_parts_toblur()
def get_parts_to_blur():
parts_to_blur={}
for item in betaconfig.items_to_censor:
parts_to_blur[item] = {
'min_prob': ( betaconfig.item_overrides.get( item, {} ) ).get( 'min_prob', betaconfig.default_min_prob ),
'width_area_safety': ( betaconfig.item_overrides.get( item, {} ) ).get( 'width_area_safety', betaconfig.default_area_safety ),
'height_area_safety': ( betaconfig.item_overrides.get( item, {} ) ).get( 'height_area_safety', betaconfig.default_area_safety ),
'time_safety': ( betaconfig.item_overrides.get( item, {} ) ).get( 'time_safety', betaconfig.default_time_safety ),
'censor_style': ( betaconfig.item_overrides.get( item, {} ) ).get( 'censor_style', randomize_censor_style() ),
}
but as expected now the censor style changes every frame vor videos and in pictures it has a different style for every box, which i sometimes dislike, because the same feature (e.g. breasts) if detected individually will be censored in different styles (unless a overwrite is given)
also im very new to coding so i assume my code is not very elegant and could be done way better ;)
Nice work! These are some great first steps. I agree, having the censor change every frame is probably not a great user experience. There are maybe a couple of things I would suggest here, what do you think?
I've written something to fix the different censor methods on the same label, which works well I think:
In betautils_censor.py :
def censor_img_for_boxes( image, boxes ):
# if 2 boxes have the same item censor_style will be set to the same style
for i in range(len(boxes)):
for j in range(len(boxes)):
if boxes[i]['label'] == boxes[j]['label']:
boxes[i]['censor_style'] = boxes[j]['censor_style']
boxes.sort( key=lambda x: ( x['label'], censor_style_sort(x['censor_style']) ) )
pieces = []
for box in boxes:
if len( pieces ) and pieces[-1][0]['label'] == box['label'] and pieces[-1][0]['censor_style']==box['censor_style']:
pieces[-1].append(box)
else:
pieces.append([box])
for piece in pieces:
collapsed_boxes = collapse_boxes_for_style( piece )
for collapsed_box in collapsed_boxes:
image = censor_image( image, collapsed_box )
image = watermark_image( image )
return( image )
Now it works kind of well for images. Since I am not very far in understanding the code for video censoring and live censoring, this will probably be it for a while.
If I get a good enough understanding of these I might try to implement the suggested improvements for random censoring for these as well, but it might take a while. If (and that's a big if ;) ) I get that working, then I might try to clean up the code.
Hey,
I've played around with my code a bit and tried to implement your suggestions as well as some very basic "feature tracking" for betatv and betavision. I am at a point now, where i feel like it works as good as I can get it to work.
Do you have any interest in reviewing / testing the code?
As of this moment my changes are:
to betaconfig.py: add:
##################################################################
#### If random censoring is chosen, on every frame that is censored
#### a new censor method is chosen and will be applied.
#### feature_tracking_tolerance is the max distance the same feature
#### e.g. covered_breast can move during 2 frames at which censoring
#### is calculated (see video_censor_fps) to keep the same censoring
#### method. 0.5 means it can "travel" and change up to 50% of the
#### video size. Further testing required for a good value.
#### Heavily increasing default_time_safety (I have it to .9)
#### recommended to achieve decent results
feature_tracking_tolerance = 0.5
add:
default_censor_style = [ 'random', [ 500,['pixel',10], 25,['bar',(0,0,0)], 500,['blur',10], 25,['bar',(247,154,192)], 1,['debug',[0,0,0]] ] ] # Randomizes the censoring between the methods according to weights
to betautils_censor.py added:
def randomize_censor_styles(boxes):
for i in range(len(boxes)):
if boxes[i]['censor_style'][0] == 'random':
boxes[i]['censor_style'] = randomize_censor_style()
for j in range(len(boxes)):
if boxes[i]['censor_style'] != boxes[j]['censor_style']:
labelstring_i = str(boxes[i]['label']).split('_')
labelstring_j = str(boxes[j]['label']).split('_')
if labelstring_i[1] == labelstring_j[1]:
boxes[j]['censor_style'] = boxes[i]['censor_style']
return (boxes)
def randomize_censor_style():
censor_style_rnd = []
perc_range = []
total = 0
rnd_censor_var = random.uniform(0,1)
if betaconfig.default_censor_style[0] == 'random':
random_censor_styles_loc = betaconfig.default_censor_style[1]
rand_sum = sum(random_censor_styles_loc[0:len(random_censor_styles_loc):2])
for n in range(0,len(random_censor_styles_loc),2):
weight = int(random_censor_styles_loc[n]) / int(rand_sum)
total = total + weight
perc_range.append(total)
if len(random_censor_styles_loc) % 2 != 0:
print('Error: your random_censor_styles seems to miss something: Check the values after default_censor_style in betaconfig.py')
chosen_random_censor_style = list(map(lambda i: i> rnd_censor_var, perc_range)).index(True)
censor_style_rnd = random_censor_styles_loc[2*chosen_random_censor_style+1]
return (censor_style_rnd)
and
def compare_boxes(live_boxes, vid_w, vid_h):
for i in range(len(live_boxes)):
if live_boxes[i]['censor_style'][0] == 'random':
for j in range(len(live_boxes)):
if i != j and live_boxes[i]['label'] == live_boxes[j]['label']:
diff_x = abs(live_boxes[i]['x'] - live_boxes[j]['x'])
diff_y = abs(live_boxes[i]['y'] - live_boxes[j]['y'])
diff_w = abs(live_boxes[i]['w'] - live_boxes[j]['w'])
diff_h = abs(live_boxes[i]['h'] - live_boxes[j]['h'])
if diff_x <= betaconfig.feature_tracking_tolerance * vid_w and diff_y <= betaconfig.feature_tracking_tolerance * vid_h and diff_w <= betaconfig.feature_tracking_tolerance * vid_w and diff_h <= betaconfig.feature_tracking_tolerance * vid_h:
if live_boxes[i]['censor_style'][0] == 'random' and live_boxes[i]['censor_style'] != live_boxes[j]['censor_style']:
live_boxes[i]['censor_style'] = live_boxes[j]['censor_style']
return (live_boxes)
and before line 151 added:
boxes = randomize_censor_styles(boxes)
to betatv.py before line 138 added:
live_boxes = bu_censor.compare_boxes(live_boxes, vid_w, vid_h)
to betavision_censor.py before line 97 added:
live_boxes = bu_censor.compare_boxes(live_boxes, betaconfig.vision_cap_width, betaconfig.vision_cap_height)
Thanks! I'm travelling this week but will definitely look when I can get when I get back.
I've created a fork where I've added my code for easier use: https://github.com/teasey/BetaSuite
I've also implemented stickers over censors in a very similar way, which works great for pictures, very good for videos with certain settings and not very well for live censoring.
I've created a fork where I've added my code for easier use: https://github.com/teasey/BetaSuite
I've also implemented stickers over censors in a very similar way, which works great for pictures, very good for videos with certain settings and not very well for live censoring.
Hey teasey I wanted to play around with this some more but noticed you didn't include your folder structure for stickers.
edit: To be clear I got it to work, but just giving a heads up. For anyone else trying you will need to create folders and fill them with png or jpg images within the main Betasuite folder for each class label called by betaconst.py as well as an 'all' folder.
stickers │ ├── all │ ├── square │ └── wide │ ├── exposed_armpits │ ├── square │ └── wide │ ├── covered_belly │ ├── square │ └── wide │ └── ...
i would like to suggest a weight option on the censor methods (0-1) and then pick the censor method by those weights, say the setting is 1 pixel, 1 blur, 0.5 bar then the percentages would be 0.4, 0.4 0.2.