Only Last frame of a video displayed in Xcode Simulator - objective-c

I'm applying some signal-processing techniques to a video by extracting a frame from the video and displaying the result to the image view before extracting the next frame. In my program, inside the -(void)viewDidload{}, I have a while loop that loops through 30 images and displays each one to the view. The problem I am having is that the image view ( UIImageView) never shows the image at each loop and only displays the last image. I want the new image to be shown every time a new frame is extracted.
I checked that the code is looping through all the images extracted from the video by pure outing frame count inside the while loop, but the imageview shows nothing.
Here is the problem code:
#interface ViewController () {
UIImageView *imageView_;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
imageView_ = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 190, 190)];
imageView_.contentMode = UIViewContentModeScaleAspectFill;
string data = "eyesample.mp4";
cv::VideoCapture original_video_data;
original_video_data.open(data);
int count = 0;
int total;
int nFrames;
cv::Mat frame;
frame = NULL;
total = original_video_data.get(cv::CAP_PROP_FRAME_COUNT);
cout <<"the total number of frames are :" << total << endl;
while (count < 30)
{
original_video_data >> frame ;
if (frame.empty()) {
break;
}
nFrames = original_video_data.get(cv::CAP_PROP_POS_FRAMES); // frame elemnt counter
cout << "Frame: " << nFrames << endl;
cout << count++ << endl;
imageView_.image = MatToUIImage(frame);
[self.view addSubview:imageView_];
}
original_video_data.release();
}

Related

Image generator ( generateCGImagesAsynchronouslyForTimes method) doesn't give live results

Pretty new to cocoa development and really stuck with probably a fundamental problem.
So in short, my app UI looks like a simple window with a nsslider at the bottom. What I need is to generate N images and place them, onto N nsviews in my app window.
What it does so far:
I'm clicking on the slider (holding it) and dragging it. While I'm dragging it nothing happens to my views (pictures are not generated). When I release the slider the pictures got generated and my view get filled with them.
What I want:
- I need the views to be filled with pictures as I'm moving the slider.
I figured out the little check box on the NSSlider properties, which is continuous, and I'm using it, but my image generator still doesn't do anything until I release the slider.
Here is my code:
// slider move action
- (IBAction)sliderMove:(id)sender
{
[self generateProcess:[_slider floatValue];
}
// generation process
- (void) generateProcess:(Float64) startPoint
{
// create an array of times for frames to display
NSMutableArray *stops = [[NSMutableArray alloc] init];
for (int j = 0; j < _numOfFramesToDisplay; j++)
{
CMTime time = CMTimeMakeWithSeconds(startPoint, 60000);
[stops addObject:[NSValue valueWithCMTime:time]];
_currentPosition = initialTime; // set the current position to the last frame displayed
startPoint+=0.04; // the step between frames is 0.04sec
}
__block CMTime lastTime = CMTimeMake(-1, 1);
__block int count = 0;
[_imageGenerator generateCGImagesAsynchronouslyForTimes:stops
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,AVAssetImageGeneratorResult result, NSError *error)
{
if (result == AVAssetImageGeneratorSucceeded)
{
if (CMTimeCompare(actualTime, lastTime) != 0)
{
NSLog(#"new frame found");
lastTime = actualTime;
}
else
{
NSLog(#"skipping");
return;
}
// place the image onto the view
NSRect rect = CGRectMake((count+0.5) * 110, 500, 100, 100);
NSImageView *iView = [[NSImageView alloc] initWithFrame:rect];
[iView setImageScaling:NSScaleToFit];
NSImage *myImage = [[NSImage alloc] initWithCGImage:image size:(NSSize){50.0,50.0}];
[iView setImage:myImage];
[self.windowForSheet.contentView addSubview: iView];
[_viewsToRemove addObject:iView];
}
if (result == AVAssetImageGeneratorFailed)
{
NSLog(#"Failed with error: %#", [error localizedDescription]);
}
if (result == AVAssetImageGeneratorCancelled)
{
NSLog(#"Canceled");
}
count++;
}];
}
}
If you have any thoughts or ideas, please share with me, I will really appreciate it!
Thank you
In order to make your NSSlider continuous, open your window controller's XIB file in Interface Builder and click on the NSSlider. Then, open the Utilities area
select the Attributes Inspector
and check the "Continuous" checkbox
under the Control header. Once you've done this, your IBAction sliderMove: will be called as the slider is moved rather than once the mouse is released.
Note: Alternatively, with an
NSSlider *slider = //...
one can simply call
[slider setContinuous:YES];

UILabel Dynamic Content auto size trouble

Please, I need some help with some UILabels that must hold dynamic content. They are contained in a UIScrollView.
I can't get them to resize properly depending on screen orientation. I also want to keep an exact distance between them.
Right now, I'm having trouble with 2 of them (many to come).
I'm using the following code to resize them but it doesn't get me the expected results:
- (void) updateLabelsPositionForPortrait
{
summary_PersonalMonth.numberOfLines = 0;
summary_PersonalDay.numberOfLines = 0;
summary_PersonalMonth.frame = CGRectMake(summary_PersonalMonth.frame.origin.x,
summary_PersonalMonth.frame.origin.y,
summary_PersonalMonth.frame.size.width + 15,
summary_PersonalMonth.frame.size.height);
[summary_PersonalMonth sizeToFit];
summary_PersonalDay.frame = CGRectMake(summary_PersonalDay.frame.origin.x,
summary_PersonalDay.frame.origin.y + summary_PersonalMonth.bounds.origin.y + 10,
summary_PersonalDay.frame.size.width + 15,
summary_PersonalDay.frame.size.height);
[summary_PersonalDay sizeToFit];
[self updateScrollViewContentSize];
}
- (void) updateLabelsPositionForLandscape
{
summary_PersonalMonth.numberOfLines = 1;
summary_PersonalDay.numberOfLines = 1;
summary_PersonalMonth.frame = CGRectMake(summary_PersonalMonth.frame.origin.x,
summary_PersonalMonth.frame.origin.y,
summary_PersonalMonth.frame.size.width,
summary_PersonalMonth.frame.size.height);
[summary_PersonalMonth sizeToFit];
summary_PersonalDay.frame = CGRectMake(summary_PersonalDay.frame.origin.x,
summary_PersonalDay.frame.origin.y - summary_PersonalMonth.bounds.origin.y - 10,
summary_PersonalDay.frame.size.width,
summary_PersonalDay.frame.size.height);
[summary_PersonalDay sizeToFit];
}
and I call each method in shouldAutorotateToInterfaceOrientation: in the corresponding orientation.
if (UIInterfaceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
[self updateLabelsPositionForPortrait];
}
else
{
[self updateLabelsPositionForLandscape];
}
The results are these:
Initial result on view load
Result after rotation in Landscape
Result after rotating back to portrait
Please, I need advice !
Thank you !
Store all labels starting form first to last in position in NSArray.
Now making one function which set frames of labels according to orientation:
-(void)setFramesOfLabel:(BOOL)flag
{
if(flag) //portrait
{
int height = 20;
int spaceBetweenLabels = 20;
itn xspace = 20 //
}
else//landscape changes
{
int height = 20;
int spaceBetweenLabels = 20;
itn xspace = 20 /
}
int count = 0;
for(UILabel *label in arrLabels)
{
NSString *strText = [arrTexts objectAtIndex:count]; //as u may having text array to fill in labels as i assume
CGSize expectedLabelSize = [strText sizeWithFont:label.font constrainedToSize:maximumLabelSize lineBreakMode:UILineBreakModeWordWrap]; //
CGrect *newFrame = CGRectMake(xspace,height,expectedLabelSize.width,expectedLabelSize.height);
[label setFrame:newFrame];
height += expectedLabelSize.height;
count ++;
}
[scrollView setContentSize(scrollView.width,height)];
}
Use
if (UIInterfaceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
[self setFramesOfLabel:TRUE];
}
else
{
[self setFramesOfLabel:FALSE];
}
You seem to be re-operating on the same frames over and over again. Try using this code:
// Declare the below variables as globals
CGRect defaultRectPortrait = CGRectZero;
CGRect defaultRectLandscape = CGRectZero;
- (void) updateLabelsPositionForPortrait
{
summary_PersonalMonth.numberOfLines = 0;
summary_PersonalDay.numberOfLines = 0;
if(defaultRectPortait == CGRectZero)
defaultRectPortait = CGRectMake(summary_PersonalMonth.frame.origin.x,
summary_PersonalMonth.frame.origin.y,
summary_PersonalMonth.frame.size.width + 15,
summary_PersonalMonth.frame.size.height);
[summary_PersonalMonth setFrame:defaultRectPortrait];
[summary_PersonalMonth sizeToFit];
// Do a similar thing for summary_PersonalDay
[self updateScrollViewContentSize];
}
- (void) updateLabelsPositionForLandscape
{
// Use similar logic for summary_PersonalMonth and summary_PersonalDay in landscape as well
}
And finally:
if (UIInterfaceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
[self updateLabelsPositionForPortrait];
}
else
{
[self updateLabelsPositionForLandscape];
}

Positioning Multiple UIImage's - Objective C

In the app I'm building, a square image is imported, it is broken into 16 tiles, and those tiles are placed in a square on the screen, starting from the top. However, I'm adding an extra bar of info at the top above the tiles, so I need to move the set of tiles further down the screen. I've played around with the for loop and the coordinates that the code makes, but nothing is giving me the desired respect.
-(void) initPuzzle:(NSString *) imagePath{
UIImage *orgImage = [UIImage imageNamed:imagePath];
if( orgImage == nil ){
return;
}
[self.tiles removeAllObjects];
tileWidth = orgImage.size.width/NUM_HORIZONTAL_PIECES;
tileHeight = orgImage.size.height/NUM_VERTICAL_PIECES;
blankPosition = CGPointMake( NUM_HORIZONTAL_PIECES-1, NUM_VERTICAL_PIECES-1 );
for( int x=0; x<NUM_HORIZONTAL_PIECES; x++ ){
for( int y=0; y<NUM_VERTICAL_PIECES; y++ ){
// *** The coordinates need to be altered - ?
CGPoint orgPosition = CGPointMake(x,y);
if( blankPosition.x == orgPosition.x && blankPosition.y == orgPosition.y ){
continue;
}
CGRect frame = CGRectMake(tileWidth*x, tileHeight*y,
tileWidth, tileHeight );
CGImageRef tileImageRef = CGImageCreateWithImageInRect( orgImage.CGImage, frame );
UIImage *tileImage = [UIImage imageWithCGImage:tileImageRef];
CGRect tileFrame = CGRectMake((tileWidth+TILE_SPACING)*x, (tileHeight+TILE_SPACING)*y,
tileWidth, tileHeight );
tileImageView = [[Tile alloc] initWithImage:tileImage];
tileImageView.frame = tileFrame;
tileImageView.originalPosition = orgPosition;
tileImageView.currentPosition = orgPosition;
CGImageRelease( tileImageRef );
[tiles addObject:tileImageView];
// now add to view
[self.view insertSubview:tileImageView atIndex:0];
}
}
[self shuffle];
}
int topBarWidth = 100; //100 based on the example in your comment
Then at the point in your code where you're setting the frames of each tile, add topBarWidth to whatever y value you were previously setting.
Another option is to create a subview just for your tiles and then reposition that instead. If you then wanted to animate all the tiles moving up and down you'd only have to animate the tiles view, instead of recalculating the position of all the images.

Set UIImage based on tag

I'm working on a script that loops through an array of LED UIImageView's that are setup in numerical order and are selected by tag. Depending on the step (aka number) it's on the led image is shown as on or off. The main goal of this method is to take the current step and display the "LED on" image while subtracting it by one and display the "LED off" image for the previous step. So, only one LED should be lit up at a time.
Unfortunately, I can only get the "LED on" image to display correctly. All of the LED's in the sequence light up, but they never turn off. My first guess is that I'm not subtracting the NSInterger in the right way. However, when I check the log, everything is where it should be. If the current step is 2, previous is 1. No idea why this isn't working. Thanks!
sequencerLocation and previousLocation are both setup as properties.
- (void)clockLoop:(UInt8)seqClockPulse
{
//cast to an int to use in loop
NSInteger stepCount = sequencerSteps;
//increment sequencer on pulse in
sequencerLocation++;
if(sequencerLocation > stepCount)
{
sequencerLocation = 1;
}
//setup previous step location
previousLocation = (sequencerLocation - 1);
if (previousLocation == 0)
{
previousLocation = stepCount;
}
//change led color in led array
for (UIImageView *led in sequencerLEDArray)
{
if(led.tag == sequencerLocation)
{
UIImageView *previousLed = (UIImageView *)[led viewWithTag:previousLocation];
[previousLed setImage:[UIImage imageNamed:#"images/seq_LED_off.png"]];
NSLog(#"Previous: %d", previousLocation);
UIImageView *currentLed = (UIImageView *)[led viewWithTag:sequencerLocation];
[currentLed setImage:[UIImage imageNamed:#"images/seq_LED_on.png"]];
NSLog(#"Current: %d", sequencerLocation);
}
}
}
//change led color in led array
for (UIImageView *led in sequencerLEDArray)
{
if(led.tag == sequencerLocation)
{
// I THINK the problem is here
// UIImageView *previousLed = (UIImageView *)[led viewWithTag:previousLocation];
// TRY THIS instead
UIImageView *previousLed = [led.superview viewWithTag:previousLocation];
[previousLed setImage:[UIImage imageNamed:#"images/seq_LED_off.png"]];
NSLog(#"Previous: %d", previousLocation);
// HERE you don't need to search for the tag you already tested for it in your if statement
UIImageView *currentLed = (UIImageView *)[led viewWithTag:sequencerLocation];
[currentLed setImage:[UIImage imageNamed:#"images/seq_LED_on.png"]];
NSLog(#"Current: %d", sequencerLocation);
}
}
viewWithTag:
Discussion
This method searches the current view and all of its subviews for the specified view.
So when you search for led by it's tag from itself, it's returning itself, but when you search its brother it's not finding it, that is why I'm suggesting the led.superview as the place to search for your tag, the parent should be able to find its other child.

Display grid view of videos

I'm trying to display a grid view in a portrait and horizontal view of the iPad. Right now im just trying to pull this off on the portrait view, so you will see the according X, Y in the following code where i'm stuck.
- (void)renderPlaylist {
cellsArray = [[NSMutableArray alloc] init];
CGFloat xPos = 0.0f;
CGFloat yPos = 0.0f;
int i = 4;
int y = 1;
int p = 1;
for (BCVideo *video in [[self playlist] videos]) {
if (i > 0) {
ScrollCellViewController *cell = [[ScrollCellViewController alloc] initWithBCVideo:video];
[cell setDelegate:self];
[[cell view] setFrame:CGRectMake(xPos, yPos, 768.0f, 245.0f)];
[scrollView addSubview:[cell view]];
[cellsArray addObject:cell];
yPos = y * 235.0f;
y++;
i--;
}else{
i = 4;
xPos = p * 245.0f;
yPos = 0.0f;
y = 1;
p++;
}
//blabla lazy
CGSize size = CGSizeMake(2000.0f, 2000.0f);
[scrollView setContentSize:size];
}
}
The total of videos is 17. I want to display 4 videos in each row, and then move right, for the next row, the scroll view will be horizontal (like the TED app). It obviously needs to display four rows of 4, and then one row of 1. This currently outputs 3 rows of 4, and then 1 of 2. For a total of 14?
what?
exactly.
If i adjust the code to rows of 5, you get a total of 15 videos. If i just the code to rows of 6, you get a total of 16 videos.
Screenshot http://i53.tinypic.com/15oj687.png
Your code is wrong in several parts.
By following it and calling U the upper part of the "if" and L the lower part of the if, you repeat this pattern:
UUUULUUUULUUUULUU
Now every 4th U you calculate y=4*235=940 as upper-left corner and it is probably out of your view (e.g. if you have a navigation bar your view height will be exactly 940 pixels height!). So the 4th row is not visible because out of screen.
Besides each U cycle draws a view which is 768px wide and 245 high so it is an horizontal stripe. Now the first 3 Us from the first three videos draw the first three lines, the 4th U draws the line out of screen. Then the "L" does nothing, it skips the video (sic!) and set "p" such that the next sequence of 4 stripes will be shifted 245px right, which is probably buggy as the stripes are still 768px wide, so the next cycles these stripes will be partially out of screen (over the right border). Besides when you will start drawing the second sequence of UUUU you will overwrite them over the existing ones but shifted 245px right.
Well, I don't know what you want to do, but it seems quite complex for a grid and it is obviously buggy. You should take care of your "swiping" code before and then you can debug it by printing in the console the position of all your videos and try to debug it. Don't try to fix it by looking for magic numbers in the parameters.
Solution:
- (void)renderPlaylist {
cellsArray = [[NSMutableArray alloc] init];
CGFloat xPos = 0.0f;
CGFloat yPos = 0.0f;
// y => counter for position of vertical videos
int y = -1;
// p => number of rows
int p = 0;
// r => check
int r = 0;
for (BCVideo *video in [[self playlist] videos]) {
r++;
// vertical rows
if (y < 3) {
y++;
yPos = y * 200.0f;
}else{
// move sideways to the right one row, and reset the vertical row
p++;
xPos = p * 255.0f;
yPos = 0.0f;
y = 0;
}
//print video
ScrollCellViewController *cell = [[ScrollCellViewController alloc] initWithBCVideo:video];
[cell setDelegate:self];
[[cell view] setFrame:CGRectMake(xPos, yPos, 255.0f, 210.0f)];
[scrollView addSubview:[cell view]];
[cellsArray addObject:cell];
CGSize size = CGSizeMake(xPos + 250.0f, 1024.0f);
[scrollView setContentSize:size];
}
}