Monday, January 28, 2019

VR180 to 3D SBS Converter

With the release of Lenovo Mirage Camera , 3D imagery has became more consumer friendly than ever before. Mirage Camera produces 3D images in a format called as "VR Jpeg -  pictures – (dual) equi-rectangular" which is a new format that is referred as VR180  released by Google.

VR180 provides a unique encoding of 3D image, where the left and right eye are merged as one image, which makes it possible to view the otherwise 3D image as a simple 2D image. However using software such as Daydream or Google photo's such VR180 photos can be viewed in true 3D.

Oculus Go is an other popular consumer friendly VR device released in 2018,  that most people use to consume VR and 3D content. By default, a VR180 picture being (more or less) proprietary to Google platform is not visible in Oculus Go. On the other hand most player's such as Pisagus VR
are fully capable of rendering standard 3D content which typically contain the image taken with left camera and right camera side-by-side.

This software "VR180 to 3D SBS" converter is an attempt to convert VR180 pictures to 3D SBS images. I got the idea from the original "BatchConverterVRtoSBS" written by Timo Fleisch. This version provides additional functionality to not only generate side-by-side images from VR180 images ( as Timo's version does ), but also facilitates splitting the VR180 images to left and right images, for individual editing and allows the individual left and right images to be merged to a single 3D Side-by-Side image.




What do this software do ?
  • Allows generation of a 3D Side-by-Side (SBS) file from VR180 picture/image file ( generated by Mirage Camera )



  • Allows extraction of left and right eye image files as separate image files from VR180 picture/image file ( for editing in your favorite imaging software like PaintShop Pro )

  • Allows generation of a 3D Side-by-Side (SBS) picture/image file from separate left and right eye image files 

How to get it ?
Thanks and credits to :


Sunday, April 15, 2018

My second AWS Certification - CSAA

After close to 2 months of effort, following my AWS Certified Developer Associate certification, I managed to secure AWS Certified Solution Architect associate on March 31st. I scored 85% , with the following distribution among the topics: 




The journey to CSAA hasn't been a easy one with requiring close to 120 hours of reading and practice. Along the path, I used my resources which provided very useful for my Developer exam, namely  acloud.guru , Udemy, Whiz labs and finally the really comprehensive guide on AWS services published by Sybex called "AWS Certified Solution Architect Official Study Guide"

Compared to the developer - associate exam, solution architect covers a wider variety of techniques and tools, although not by a drastic amount. Following are the topics that are new for CSAA exam, in comparison with the CDA exam:

  • Auto scaling
  • MySQL
  • Aurora
  • Redshift
  • Kinesis
  • API Gateway
  • Consolidated Billing & AWS Organizations

Once again I utilized my 1-2-4-7 tool, which proved to be a very powerful tool in this preparation. I am amazed by how well ingrained the AWS concepts are in my mind, as I am only days away from the exam, without requiring to revisit them. My last days before exam are just spent doing practice exams, making a very efficient use of my time. 

In my view, the future of IT industry is going to be heavily oriented towards cloud and having a preliminary knowledge of different cloud services & offerings is a must-have for most IT professionals. To assist the community, I will be publishing periodic articles on several AWS Cloud services & offerings. My goal is to be brief and succinct so that the reader can have a preliminary and basic understanding of the topic for any future discussions or exploration. 

Finally, I present my certificate the result of my hours of effort here: AWS CSAA Certificate

Sunday, February 4, 2018

Designing a efficient revision system (personal use) - using Google Apps Script ( Part 2 )

In my previous article about designing a efficient revision system using Google Apps Script, a study-aid, I discussed the steps involved in the setup, of Google Sheet as a Database store, and Google sheet for collecting information.
The goal of this article is to describe the engine that drives that system, in few simple steps, and by the end of this article the reader will be familiarized with the idea, of how to program Google sheets, to calculate the days of revision and setup Google Calendar events, for those days.
So let me start with defining what we expect this program to accomplish, in technical terms, the requirements:
1) Calculate the following days of revision, based on first study date: 2, 4, 7, 30, 60, 90
2) Set calendar (in this case, google calendar) events on the revision days mentioned
3) Send a email of the revision plan for each recorded topic, once setup
So let us start...
Step 1) Creating your helper methods in Script Editor:
Open the script editor from the Google spreadsheet that you set up in the last article, from Tools > Script Editor

Now add the following helper methods in your Script editor:
getColIndexByName() finds the column number based on column name.
It utilizes the SpreadsheetApp class to find the active sheet, and the index number of the column, based on the column name, that is passed in. So in summary, it answers the question "What column number does this column name belong to?"
/*
The getColIndexByName helper function returns the column index for a given column name.

*/

function getColIndexByName(colName{
  var sheet = SpreadsheetApp.getActiveSheet();
  var numColumns = sheet.getLastColumn();
  var row = sheet.getRange(1, 1, 1, numColumns).getValues();
  for (i in row[0]) {
    var name = row[0][i];
    if (name == colName) {
      return parseInt(i) + 1;
    }
  }
  return -1;
}
correctTheDate() method is used to correct a issue noticed in google forms.
It is noticed that when the date that is being entered is being set to the 11PM of the previous day. It may be a issue due to the Timezone differences, and hence it is adjusted to the next day, if the data entered as the "first study date" in the google form is being recorded as 11PM of the previous day.
/*
  2017-10-31 SK: Since 2017-10-30, it is noticed that the entries 
into "First Study Date" column, from the form are always in date format, 
and that the date, which has no time component in form is set to 23:00 (11 pm) 
of previous day to the actual date entered on the form. 
  
So a correction is introduced to correct the day, if 23:00 is noticed in 
the time component. Day is adjusted to the next day of the value 
in "first study date" column, which is the actual date entered in the form. 
  
 getHours() is a javascript Date class method
*/
function correctTheDate(DayDateEntered)
{
  //Browser.msgBox("getHours() is " + Day1Date.getHours());
  if(DayDateEntered.getHours() == 23)
  {
    DayDateEntered.setDate(DayDateEntered.getDate() + 1);
  } 
  return DayDateEntered;
}
addDate() method adds a given number of days to a given date.
Date & time is maintained internally inside a computer, as a count of the number of milliseconds that has passed since Jan 1, 1970. To calculate any number of seconds from a given date we convert a given date to milliseconds since epoch, and add it to the number of days, we want to add, converted to milliseconds. Finally, we convert the total number of milliseconds to date, and we will have the given date advanced by the given number of days
/*
2017-10-06 SK : Adds days by converting them to milliseconds

*/
function addDays(date,numDays) {
    //converts number of days to add in Ms
    var timeinMs = numDays * 24 * 60 * 60 * 1000;
    //gets the current date in milliseconds since epoch 1970
    var curDtInMs = date.getTime();
    var newTimeInMs = curDtInMs + timeinMs
    var newDate = new Date();
    //create new date from the sum of milliseconds since epoch
    newDate.setTime(newTimeInMs);
    return newDate;
}

As you will soon see, we use this addDays() method to calculate our 2nd, 4th study dates and so on, for our revision schedule, correctTheDate() to address issues with the First study date, and getColIndexByName() to quickly locate the columns by their name.
Step 2) Creating your form submit method :
setRevisionSchedule() calculates the revision dates, sets the calendar events and e-mails the revision summary
This method which gets triggered on submission of linked Google form, (trigger set up will be in next step) will accomplish the following steps, in that order:
  1. Calculate and set the revision dates in the respective spreadsheet columns
  2. Set the calendar events corresponding to revision dates with a email reminder, 5 minutes before event commencement using CalendarApp class, in the default users calendar
  3. Finally, sends a email of the revision schedule summary using MailApp and the sendEmail() method to the user's default email address.
/*

Calculates the revision dates, sets the calendar events and e-mails the summary, for the the last 
row in the active sheet if the "Calendar Set?" column is not set to "yes" when the method is triggered 

Finally it will set the value in the "Calendar Set?" column for that row to 'Yes', to prevent it from being set in future. 

*/
function setRevisionSchedule(e)
{
  var sheet = SpreadsheetApp.getActiveSheet();
  var lastRow = sheet.getLastRow();
  
  var isCalendarSet = sheet.getRange(lastRow, getColIndexByName("Calenadar Set ?")).getValue();
  
  if(isCalendarSet != "yes" && lastRow > 1)
  {
    var LearningSourceTitle = sheet.getRange(lastRow, getColIndexByName("Learning Source Title")).getValue();
    var SubSection = sheet.getRange(lastRow, getColIndexByName("Sub Section")).getValue();
    var Day1Date = new Date(sheet.getRange(lastRow, getColIndexByName("First Study Date")).getValue());
    Day1Date = correctTheDate(Day1Date);
    //Browser.msgBox(Day1Date);
    
    var DayNextRev = new Date(Day1Date);

    //Set the "2nd Day Revision"
    DayNextRev = addDays(Day1Date,1);
    sheet.getRange(lastRow, getColIndexByName("2nd Day Revision")).setValue(DayNextRev);
    var Day2 = "2nd Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 2nd day 
    var DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("2nd Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '2nd Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);   
    
    
    //Set the "4th Day Revision"
    DayNextRev = addDays(Day1Date,3);
    sheet.getRange(lastRow, getColIndexByName("4th Day Revision")).setValue(DayNextRev);
    var Day4 = "4th Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 4th day 
    var DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("4th Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '4nd Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);
    
    //Set the "7th Day Revision"
    DayNextRev = addDays(Day1Date,6);
    sheet.getRange(lastRow, getColIndexByName("7th Day Revision")).setValue(DayNextRev);
    var Day7 = "7th Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 7th day
    var DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("7th Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '7th Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);
    
    //Set the "30 Day Revision"
    DayNextRev = addDays(Day1Date,29);
    sheet.getRange(lastRow, getColIndexByName("30 Day Revision")).setValue(DayNextRev);
    var Day30 = "30 Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 30th day
    DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("30 Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '30 Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);
    
    //Set the "60 Day Revision"
    DayNextRev = addDays(Day1Date,59);
    sheet.getRange(lastRow, getColIndexByName("60 Day Revision")).setValue(DayNextRev);
    var Day60 = "60 Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 60th day
    DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("60 Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '60 Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);
    
    //Set the "90 Day Revision"
    DayNextRev = addDays(Day1Date,89);
    sheet.getRange(lastRow, getColIndexByName("90 Day Revision")).setValue(DayNextRev);
    var Day90 = "90 Day Revision is Scheduled on " + DayNextRev.toDateString()
    // Creates an all-day event with email reminder for calendar, on the 90th day
    DayNextRevEvent = CalendarApp.getDefaultCalendar().createAllDayEvent("90 Day Revision of Title: " + LearningSourceTitle + " | Sub: " + SubSection,DayNextRev,{Description: '90 Day revision based on 1-2-4-7 principle'});
    DayNextRevEvent.addEmailReminder(5);
    
    //Record the fact that calendar is set, for this row
    sheet.getRange(lastRow, getColIndexByName("Calenadar Set ?")).setValue("yes");
    
    //Obtain the current active users email address to email the revision schedule
    var userEmail = Session.getActiveUser().getEmail(); 
    
    //send the email of the summary revision schedule
    MailApp.sendEmail({
      to: userEmail,
      subject: "Revision Schedule for Title: " + LearningSourceTitle + " | Sub: " + SubSection,
      htmlBody: "<h2><b>Revision is Scheduled for Title: " + LearningSourceTitle + " | Sub: " + SubSection + "</b></h2><br><hr><br>" +
      Day2 +  "<br> " +
      Day4 +  "<br> " +
      Day7  + "<br>" +
      Day30 + "<br> " +
      Day60 + "<br> " +
      Day90 + "<br><br>" +
      " <h3>---- THE 1-2-4-7 System ------</h3><br>"
    });
  
  }
}
Step 3) Setting up trigger, for your form submit method :
As mentioned, in the previous step method setRevisionSchedule() needs to be triggered when the linked Google form, which records the Study details, is submitted.
This is performed using the Edit > Current project's triggers option in the Script editor.

Select the method "setRevisionSchedule()" for the dropdown, under "Run" column, and "From spreadsheet" for the Events. Time-driven events, are for when you would like to perform events on a schedule, which does not fit our current requirement.
For, when to trigger the method, select "On form submit", since that is when we want our method "setRevisionSchedule()" to run.
That is it. You now have a very efficient and organized study-aid. All that is left now is to grab the link for the google form, and start using it. This leads to our next step.
Step 4) Grab the link, for the study-aid :
The link for the Google form, which allows us to enter the information regarding the topic of study, and the first study date, can be obtained using the "Form" menu on the associated Google Spreadsheet.

This will lead to the form, which provides the link.

You can copy that link, bookmark it, or embed it in your own webpage and use it to access the form for your study-aid. Please bear in mind, that you will be requested to provide our script necessary permissions to run and modify your Google Spreadsheets, the first time you run it.
Thank you for patiently following these steps and congratulations, on setting-up, and programming your own study-aid, which will allow you to have a very organized revision schedule, improving your chances of retaining the topics you studied for a long time. Feel free, to comment on the article or reach out for any suggestions.

VR180 to 3D SBS Converter