我正在尝试遮罩图像,其中遮罩的值对应于列表中多个值中的任何一个。
请考虑以下“图像”和“像素值”
import numpy
img = numpy.arange(27).reshape(3,3,3) #something to represent an image
pixels = [numpy.array([0,1,2]), numpy.array([9,10,11])] #arbitrarily selected "pixel" values
我正在尝试提出一些过程,该过程将输出2d遮罩数组,其中遮罩值对应于列表pixels
中的像素值
目标:
In [93]: mask
Out[93]:
array([[1, 0, 0],
[1, 0, 0],
[0, 0, 0]])
从this answer中尝试1:
mask = numpy.zeros( img.shape[:2], dtype = "uint8" )
mask[numpy.in1d(img, pixels).reshape(mask.shape)] = 1
这导致ValueError: cannot reshape array of size 27 into shape (3,3)
我相信这个答案假设2d输入为img
尝试2:
mask = numpy.zeros(img.shape[:2])
for x,y in [(x,y) for x in range(img.shape[0]) for y in range(img.shape[1])]:
if img[x,y,:] in pixels:
mask[x,y] = 1
这将产生ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
,但可以想象有一种比遍历每个值更简洁的方法。
答案 0 :(得分:1)
设置
确保您的pixels
首先是numpy.array
:
pixels = np.array(pixels)
您可以在此处使用广播,只是要注意内存要求不是太高:
(img[:, None] == pixels[:, None]).all(-1).sum(1)
array([[1, 0, 0],
[1, 0, 0],
[0, 0, 0]])
答案 1 :(得分:0)
您将收到ValueError,因为您将np.array用作if语句的“输入”。但这必须是一个整数或一个数字。当您使用//
// ViewController.m
// VisibleViewDemo
//
// Copyright © 2018 ByteSlinger. All rights reserved.
//
#import "ViewController.h"
CG_INLINE void drawLine(UIView *view,CGPoint point1,CGPoint point2, UIColor *color, NSString *layerName) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addLineToPoint:point2];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = color.CGColor;
shapeLayer.lineWidth = 2.0;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.name = layerName;
[view.layer addSublayer:shapeLayer];
}
CG_INLINE void removeShapeLayers(UIView *view,NSString *layerName) {
if (view.layer.sublayers.count > 0) {
for (CALayer *layer in [view.layer.sublayers copy]) {
if ([layer.name isEqualToString:layerName]) {
[layer removeFromSuperlayer];
}
}
}
}
CG_INLINE void drawXBox(UIView *view, CGRect rect,UIColor *color) {
NSString *layerName = @"xbox";
removeShapeLayers(view, layerName);
CGPoint topLeft = CGPointMake(rect.origin.x,rect.origin.y);
CGPoint topRight = CGPointMake(rect.origin.x + rect.size.width,rect.origin.y);
CGPoint bottomLeft = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
CGPoint bottomRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
drawLine(view,topLeft,topRight,color,layerName);
drawLine(view,topRight,bottomRight,color,layerName);
drawLine(view,topLeft,bottomLeft,color,layerName);
drawLine(view,bottomLeft,bottomRight,color,layerName);
drawLine(view,topLeft,bottomRight,color,layerName);
drawLine(view,topRight,bottomLeft,color,layerName);
}
@interface ViewController ()
@end
@implementation ViewController
UIView *view1;
UIView *view2;
UIView *view3;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGFloat width = [UIScreen mainScreen].bounds.size.width / 2;
CGFloat height = [UIScreen mainScreen].bounds.size.height / 4;
view1 = [[UIView alloc] initWithFrame:CGRectMake(width / 2, height / 2, width, height)];
view1.backgroundColor = UIColor.yellowColor;
[self.view addSubview:view1];
[self addGestures:view1];
view2 = [[UIView alloc] initWithFrame:CGRectMake(width / 2, height / 2 + height + 16, width, height)];
view2.backgroundColor = UIColor.greenColor;
[self.view addSubview:view2];
[self addGestures:view2];
view3 = [[UIView alloc] initWithFrame:CGRectMake(10, 10, width / 2, height / 2)];
view3.backgroundColor = [UIColor.blueColor colorWithAlphaComponent:0.5];
[view1 addSubview:view3]; // this one will behave differently
[self addGestures:view3];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self checkOnScreen:view1];
[self checkOnScreen:view2];
[self checkOnScreen:view3];
}
- (IBAction)reset:(id)sender {
view1.transform = CGAffineTransformIdentity;
view2.transform = CGAffineTransformIdentity;
view3.transform = CGAffineTransformIdentity;
[self.view setNeedsLayout];
}
- (void)addGestures:(UIView *)view {
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(handlePan:)];
[view addGestureRecognizer:panGestureRecognizer];
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:@selector(handlePinch:)];
[view addGestureRecognizer:pinchGestureRecognizer];
}
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect intersection = CGRectIntersection(vc.view.bounds, frame);
// adjust the intersection coordinates thru any nested views
UIView *loopView = view;
do {
intersection = [loopView convertRect:intersection fromView:loopView.superview];
loopView = loopView.superview;
} while (loopView != vc.view);
return intersection; // may be same as the original view
}
- (void)checkOnScreen:(UIView *)view {
CGRect visibleRect = [self getVisibleRect:view];
if (CGRectEqualToRect(visibleRect, CGRectNull)) {
visibleRect = CGRectZero;
}
drawXBox(view,visibleRect,UIColor.blackColor);
}
//
// Pinch (resize) an image on the ViewController View
//
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer {
static CGAffineTransform initialTransform;
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self.view bringSubviewToFront:recognizer.view];
initialTransform = recognizer.view.transform;
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
} else {
recognizer.view.transform = CGAffineTransformScale(initialTransform,recognizer.scale,recognizer.scale);
[self checkOnScreen:recognizer.view];
[self.view setNeedsLayout]; // update subviews
}
}
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
static CGAffineTransform initialTransform;
if (recognizer.state == UIGestureRecognizerStateBegan) {
[self.view bringSubviewToFront:recognizer.view];
initialTransform = recognizer.view.transform;
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
} else {
//get the translation amount in x,y
CGPoint translation = [recognizer translationInView:recognizer.view];
recognizer.view.transform = CGAffineTransformTranslate(initialTransform,translation.x,translation.y);
[self checkOnScreen:recognizer.view];
[self.view setNeedsLayout]; // update subviews
}
}
@end
时,会将numpy数组转换为布尔值(当所有元素的差值都为零时为True)。
解决方案
numpy.all
答案 2 :(得分:0)
将您的pixels
转换为列表列表,然后可以通过简单的列表理解来做到这一点:
pixels = [list(pixel) for pixel in pixels]
mask = [[int(list(row) in pixels) for row in i] for i in img]
输出:
[[1, 0, 0], [1, 0, 0], [0, 0, 0]]
np.array
在使用==
进行比较时为每个元素返回一个值,这就是为什么在使用in
进行比较时会给您该错误的原因。 sublist in list
返回一个真值。
答案 3 :(得分:0)
我发现的一种解决方案比到目前为止的其他解决方案要快,并且所需的额外内存最少:
mask = numpy.zeros( img.shape[:2], dtype=bool )
for pixel in numpy.unique(pixels, axis=0):
mask |= (img == pixel).all(-1)