I am trying to decode barcodes that appear on a region of interest, that is 80% of the screen width and 20% of the screen height and centered on both directions (blue rectangle).
The camera pixel buffer is rotated right.
This is what Apple has to say about this orientation:
The (x,y) pixel coordinates of the origin point (0,0) represent the
top row and rightmost column, respectively. Pixel (x,y) positions
increase top-to-bottom, right-to-left. If an image is encoded with
this orientation, then displayed by software unaware of orientation
metadata, the image appears to be rotated 90° counter-clockwise. (That
is, to present the image in its intended orientation, you must rotate
it 90° clockwise.)
So, when I define the region of interest of my VNDetectBarcodesRequest I do like this:
lazy var barcodeRequest: VNDetectBarcodesRequest = {
let barcodeRequest = VNDetectBarcodesRequest {[weak self] request, error in
guard error == nil else {
print ("ERROR")
return
}
self?.classification(request)
}
barcodeRequest.regionOfInterest = CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.6)
If the bar code is inside the blue area and at any point above that, including anywhere on the area at the top of the blue area, it will detect. If the barcode is down the blue area, it will not detect anything.
Just making sure, if you look at regionOfInterest, the documentation says:
The rectangle is normalized to the dimensions of the processed image. Its origin is specified relative to the image's lower-left corner.
So the origin (0,0) is at the bottom left. With your current CGRect,
CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.6)
you are getting the expected result - "If the bar code is inside the blue area and at any point above that, including anywhere on the area at the top of the blue area, it will detect."
All you need to do is change the height from 0.6 to 0.2. You will want:
barcodeRequest.regionOfInterest = CGRect(x: 0.1,
y: 0.4,
width: 0.9,
height: 0.2) /// your height is wrong
Just to chime in here for added clarity, cuz this was also tripping me up.
The documentation for regionOfInterest says:
The default value is { { 0, 0 }, { 1, 1 } }
Which I was also confusing for 2 points (a bottom left corner and a top right corner). But that last pair is supposed to be the normalized width and height; not a normalized coordinate.
// ❌
request.regionOfInterest = CGRect(x: 0.1, y: 0.4, width: 0.9, height: 0.6)
// ✔️
request.regionOfInterest = CGRect(x: 0.1, y: 0.4, width: 0.8, height: 0.2)
Related
i'm trying to show a layout at from the bottom of an imageview to a predefined height. Unfortunately its shown at the top, not at the bottom. This is my code i have tried:
var frm: CGRect = firstImageOverlay.frame
frm.origin.x = frm.origin.x
frm.origin.y = frm.origin.y
frm.size.width = frm.size.width
frm.size.height = frm.size.height
firstImageOverlay.frame = frm
UIView.animate(withDuration: 0.5, animations: {
self.progressA.frame = CGRect(x: frm.origin.x, y: frm.origin.y, width: frm.size.width, height: self.firstImageOverlay.frame.height*CGFloat(0.4))
})
and here is the result of this code:
the light gray part shows the layout at the left imageview. this should be shown from the bottom till the defined height
iOS uses a reflected cartesian coordinate system with 0,0 in the top right and positive y pointing down and positive x pointing right, so when you draw at x: frm.origin.x, y: frm.origin.y you are saying draw from the top left down to the width and height.
You need to adjust your y coordinate down:
self.progressA.frame = CGRect(x: frm.origin.x, y: frm.origin.y + self.firstImageOverlay.frame.height*CGFloat(0.6), width: frm.size.width, height: self.firstImageOverlay.frame.height*CGFloat(0.4))
I have 4 playing cards on the screen. At the press of a button, I want one of the cards at random to move to the middle of the top half of the screen. Is it possible to create an instance of a constraint (eg: centerXAnchor with constant 0, and centerYAnchor with constant -200) so that I can use CGAffineTransform and move the random image to this point?
Ive tried creating an instance of a CGRect Frame:
let destination = CGPoint(x: 10, y: 10)
but this does not move evenly across devices.
An affine transformation matrix is used to rotate, scale, translate, or skew the objects you draw in a graphics context.
I don't think CGAffineTransform is the ideal thing to use for this task. You aren't doing any the above things (rotate, scale, translate, or skew).
I think you would likely be best using UIView.animateWithDuration
let cardSize = CGSize(width: 100, height: 100)
let card = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: cardSize))
UIView.animate(withDuration: 1.0) {
card.frame = CGRect(origin: CGPoint(x: 100, y: 100), size: cardSize)
}
let's say I have a 3d cube of this size.
Height: 1002.0
Width: 564.0
The cube size is based on image size, here's how I'm creating the cube:
let image = UIImage(named: "img")
artRoomScene.setup(height: image!.size.height / 600, width: image!.size.width / 600, position: SCNVector3(0, 0.4, -1.5), rotation: SCNVector4(0,30,0,-56))
Obviously, the cube will be way too big for any iPhone screen if I don't divide it by 600.
But instead of dividing by 600. How can I resize the cube Proportionally to the iPhone screen size?
you can use the % you want, let's say you want a 20% of the screen width:
let desiredWidth = view.frame.width * 0.2
and setup the artRoomScene
image!.size.width / desiredWidth
Using SpriteKit, I'm trying to create a rectangle as a background, with a second rectangle 25% of the size of the background and position it at the bottom of the background.
(so the lower 25% is blue, and the upper 75% is dark grey)
This is my set up:
screenWidth = size.width //312
screenHeight = size.height //390
func createSky(){
let sky = SKSpriteNode(color: SKColor.darkGray, size: CGSize(width: screenWidth, height: screenHeight))
print("Sky: ", sky.frame)
addChild(sky)
}
func createGround(){
let ground = SKShapeNode.init(rectOf: CGSize(width: screenWidth, height: screenHeight / 4))
ground.fillColor = SKColor.blue
print("Ground: ", ground.frame )
sky.addChild(ground)
}
For some reason, ground.frame is printing Ground: (-157.35, -50.1, 314.7, 100.2). Why is this? Shouldn't the last 2 figures be 312, 97.5?
I've tried various .positions and .anchorPositions but I still can't get the SKShapeNode to sit correctly within the SKSpriteNode.
Eventually the Shape will be more complex which is why I'm not using Sprite for the second one. What am I missing?
So what it looks like from your code is that you are trying to create a shapeNode and then position it inside your SKSpriteNode. Most of it you got right, you just did the positioning code incorrectly.
When you add a child to a node, that child uses the parent node as its origin point for reference. So if you tell the child node to be -50 X and 150 Y, that child node will be -50 X and 150 Y from the center point of its parent node.
When I do child nodes (especially ones that have a ton of similarities to the parent node) I like to reference the parent node for positioning, width, and height. I don't know if it might be bad practice, but its what I've done for two years now.
This is how I would have done it:
var sky = SKSpriteNode()
var ground = SKShapeNode()
func createSky() {
sky = SKSpriteNode(color: SKColor.darkGray, size: CGSize(width: self.frame.size.wdith, height: self.frame.size.height))
// self.frame.size.width/self.frame.size.height calls its info from the ViewController, which is tied directly to your screen size (unless otherwise changed)
sky.position = CGPoint(x: 0,y: 0)
self.addChild(sky)
}
func createGround() {
ground = SKShapeNode((rectOf: CGSize(width: sky.width, height: sky.height * 0.25))
ground.position = CGPoint(x: 0, y: sky.position.y - (ground.size.height / 1.5))
}
I'm trying to centre a UIView in another view (so like a pop up view), but whatever I do, I just cannot align it centrally!
func loadPopUpView() {
let customView = CGRect(x: view.center.x, y: view.center.y, width: 100, height: 100)
popUpView = UIView(frame: customView)
popUpView.backgroundColor = UIColor.black
view.addSubview(popUpView)
popUpView.isHidden = false
}
I've changed the background colour to black just so I know when it appears.
I cannot do this with storyboard because it's going on a tableView, so I'm trying to do it programmatically. Result Image
You also need to minus half value of your custom view height and width from x and y like below:
let customView = CGRect(x: view.center.x - 50, y: view.center.y - 50, width: 100, height: 100)
You are telling it to put top left corner in the center, hence you need to let it get half size in position.
let customView = CGRect(x: view.center.x-50, y: view.center.y-50, width: 100, height: 100)
Another solution is the use anchorpoints.
customView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
customView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
customView.heightAnchor.constraint(equalToConstant: 100).isActive = true
customView.widthAnchor.constraint(equalToConstant: 100).isActive = true
On CGRect(x:, y:, width:, height:), the point (x,y) is the origin. In iOS, that's the top left point.
On the CGRect doc:
In the default Core Graphics coordinate space, the origin is located
in the lower-left corner of the rectangle and the rectangle extends
towards the upper-right corner. If the context has a
flipped-coordinate space—often the case on iOS—the origin is in the
upper-left corner and the rectangle extends towards the lower-right
corner.
So to fix this:
let width = 100.0
let height = 100.0
let customViewFrame = CGRect(x: view.center.x - width/2.0, y: view.center.y - height/2.0, width: width, height: height)
Another solution would be to apply the center once the frame (especially the width/size) have been set.
let customViewFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
customViewFrame = view.center