FORUMS

[apk][mod] Lcamera with longer exposure times for crazy night pictures

191 posts
Thanks Meter: 277
 
By enryea123, Senior Member on 9th December 2016, 07:48 PM
Post Reply Email Thread

Hey everyone!

As some of you might know, the nexus 5x and nexus 6p cameras have a maximum exposure time in manual mode of 1/4.3 seconds, which is a real shame. Somebody suggested that Google made this choice because of the bigger size of the pixels, nonetheless the resulting pictures in very low light are not satisfying and none of the apps on the play store overrides the limit of 1/4.3 seconds.

So, I managed to unlock longer exposure times (up to 5 seconds) on the nexus 5x camera to take some truly unbelievable night pictures. Since the sensor is the same, this app should work also on the nexus 6p and it might work even on other devices with at least android 5.0. It also probably works on the nexus 5, but doesn't appear to be working on the nexus 6.

A big thank to PkmX for developing the original app Lcamera and to CazeW for his suggestions.

Notice that the photos will be upside down, because the sensor is mounted upside down (at least in the nexus 5x). Just rotate them with your favorite photos editor. Also notice that the "screen refresh time" is the one of the exposure, so when you set an exposure of e.g. 3 seconds, the app will look like if it's stuck and refresh every 3s.

I am not responsible for any damage that your phone might report. I've been using this app for a long time and everything works fine.
You can download the .apk file and the source code at the bottom. To install the app you only need the .apk file, the source code is for developers who wish to improve the code.

Check the difference between a manual camera downloaded from the play store and my app (the pics are resized here).
Click on the images to enlarge.

Click image for larger version

Name:	before.jpg
Views:	20380
Size:	65.2 KB
ID:	3963505Click image for larger version

Name:	after.jpg
Views:	20642
Size:	111.6 KB
ID:	3963506

How did I do it?
I exploited the fact that the older versions of Lcamera by PkmX allowed up to 1/1.2 seconds of exposure time (probably because the nexus 5x wasn't supported yet), so I downloaded the source of lcamera 0.3 by PkmX, modified a few lines of code and compiled it.
The exposure times of my modded app are: 5s, 4s, 3s, 2s, 1.5s, 1s, 0.5s, 0.23 s, ... and so on, up to 1/120000 s (the default minimum value) and you can change them in the settings of the app.

Why not more than 5 seconds?
Because the app gets really unstable, since those exposure times are not officially "hardware" supported.
EDIT: a user suggested here that the app might be stable for even longer exposures with a longer kernel readahead.
Beware that the app can be unstable even with exposure times longer than 3 seconds: if it starts crashing, just terminate it in the settings. I usually set the exposure time back to 1/10 s every time I close the app, otherwise the following times it might just crash when entering in it.
Therefore, with this app you can get some beautiful night pictures, the drawback is that sometimes it might be unstable (because those exposures are not hardware supported).

What did I modify?
In src/pkmx/lcamera/MainActivity.scala I've modified lines 417, 419, 693 and deleted the line 1083. You can download my source code at the bottom, the original source code from github and compare them, to see in more detail which are the differences.
I've also modified the app icon with one that I've personally designed.

Thank you and have fun

Attached Files
File Type: apk Lcamera1_enryea123.apk - [Click for QR Code] (546.6 KB, 29118 views)
File Type: zip source_code_for_developers.zip - [Click for QR Code] (75.7 KB, 2026 views)
The Following 68 Users Say Thank You to enryea123 For This Useful Post: [ View ] Gift enryea123 Ad-Free
9th December 2016, 08:11 PM |#2  
Senior Member
Thanks Meter: 210
 
More
The first one is Google camera and the second is from your app
Attached Thumbnails
Click image for larger version

Name:	IMG_20161209_130851.jpg
Views:	9786
Size:	249.9 KB
ID:	3963520   Click image for larger version

Name:	IMG_20161209_130913.jpg
Views:	9774
Size:	262.5 KB
ID:	3963522  
9th December 2016, 08:19 PM |#3  
enryea123's Avatar
OP Senior Member
Flag Milan
Thanks Meter: 277
 
More
Quote:
Originally Posted by TW1ST3D1NS4N3

The first one is Google camera and the second is from your app

In my app, tap on the magenta settings button, then on exposure and then de-select "Auto Exposure" and decrease the value of shooting time from 1/10 to something like 1-2, you will see what a difference.
The Following 4 Users Say Thank You to enryea123 For This Useful Post: [ View ] Gift enryea123 Ad-Free
9th December 2016, 09:31 PM |#4  
Junior Member
Flag Belgrade
Thanks Meter: 3
 
More
Thanks for this.
Is it possible to force ISO to a lower value than 60?

Sent from my Nexus 5X using Tapatalk
9th December 2016, 11:17 PM |#5  
enryea123's Avatar
OP Senior Member
Flag Milan
Thanks Meter: 277
 
More
Quote:
Originally Posted by oldskuler

Thanks for this.
Is it possible to force ISO to a lower value than 60?

Sent from my Nexus 5X using Tapatalk

Well, in the app the lowest possible iso is set to 40, but the camera doesn't go below 60, so I think it's not possible. Anyway 60 is already very low and the noise shouldn't be much, so I don't know if an even lower iso would actually bring some benefits.
10th December 2016, 12:35 AM |#6  
Senior Member
Thanks Meter: 451
 
Donate to Me
More
Good job. Some questions and tips for your code. Haven't tried the app though as my phone is getting repaired.

Why use a base of 60s? Wouldn't it have been easier to just use a 10s base instead of 60s for val exposureTime? Then you would only have needed to multiply the values by 10 in exposureTimeMap instead of 60 (and also add your values, 2 for 5s, 2.5 for 4s and so on). You also seem to be missing the base 1/60s exposure, don't know if that matters though.

Remove the line prefs.exposureTimeIndex = exposureTimeIndex() from onStop(), this will stop the manual exposure getting saved when closing the app (hence you don't need to change it back before closing).

Try replacing the line (not sure if this code will work but you probably notice what I'm trying to do)
Code:
observe { exposureTimeIndex foreach { v => text = s"60/${new DecimalFormat("#.#").format(exposureTimeMap(v))}" } }
with
Code:
observe { exposureTimeIndex foreach { v => text = if (v > 5) s"1/${new DecimalFormat("#.#").format(exposureTimeMap(v)/60)}" else s"${new DecimalFormat("#.#").format(60/exposureTimeMap(v))}s" } }
for a nicer display of the exposure times. Obviously change the value of 60 if you decide to change the base value.

EDIT: You should also be able to fix the rotation by implementing this commit in your code. Might also know how to "fix" the preview as well so the refresh rate doesn't go below a certain rate, but don't want to take away all the fun from you.
The Following 4 Users Say Thank You to CazeW For This Useful Post: [ View ] Gift CazeW Ad-Free
10th December 2016, 02:28 AM |#7  
tauio111's Avatar
Senior Member
Flag Jõhvi
Thanks Meter: 368
 
More
Nice, should be great for shooting auroras.
Attached Thumbnails
Click image for larger version

Name:	cam.jpg
Views:	7028
Size:	50.3 KB
ID:	3963778  
10th December 2016, 05:37 AM |#8  
Senior Member
Flag Bay Area California
Thanks Meter: 986
 
More
So flash the source first then install apk? Apk alone would not take a picture.
10th December 2016, 01:19 PM |#9  
tauio111's Avatar
Senior Member
Flag Jõhvi
Thanks Meter: 368
 
More
Quote:
Originally Posted by Travisdroidx2

So flash the source first then install apk? Apk alone would not take a picture.

Source is the sourcecode of the apk...
You don't have to flash anything,
The Following 2 Users Say Thank You to tauio111 For This Useful Post: [ View ] Gift tauio111 Ad-Free
10th December 2016, 02:10 PM |#10  
enryea123's Avatar
OP Senior Member
Flag Milan
Thanks Meter: 277
 
More
Quote:
Originally Posted by CazeW

Why use a base of 60s? Wouldn't it have been easier to just use a 10s base instead of 60s for val exposureTime? Then you would only have needed to multiply the values by 10 in exposureTimeMap instead of 60 (and also add your values, 2 for 5s, 2.5 for 4s and so on). You also seem to be missing the base 1/60s exposure, don't know if that matters though.

Remove the line prefs.exposureTimeIndex = exposureTimeIndex() from onStop(), this will stop the manual exposure getting saved when closing the app (hence you don't need to change it back before closing).

Try replacing the line (not sure if this code will work but you probably notice what I'm trying to do)

Code:
observe { exposureTimeIndex foreach { v => text = s"60/${new DecimalFormat("#.#").format(exposureTimeMap(v))}" } }
with
Code:
observe { exposureTimeIndex foreach { v => text = if (v > 5) s"1/${new DecimalFormat("#.#").format(exposureTimeMap(v)/60)}" else s"${new DecimalFormat("#.#").format(60/exposureTimeMap(v))}s" } }
for a nicer display of the exposure times. Obviously change the value of 60 if you decide to change the base value.

EDIT: You should also be able to fix the rotation by implementing this commit in your code. Might also know how to "fix" the preview as well so the refresh rate doesn't go below a certain rate, but don't want to take away all the fun from you.

Thank you for the suggestions! Well I choose a base 60 because it is divisible by 5,4,3,2,1, so I could avoid using "double" values for the exposures and I didn't have to worry about the digit precision, but yes I've modified the code as you suggested to have a better looking exposure time in the app, with some small differences; now it's like 5 s, 4 s, ..., 1/2 s, 1/4.3 s, ... and I've also modified a bit the shorter exposures and added back the 1/60 one.
I've also deleted the line that saves the exposure preference.
I've checked the rotation commit but it is for a newer version of Lcamera, so there are many differences in the code.
Of course any suggestion on how to fix it in my app or how to change the "screen refresh rate" is welcome , as long as it doesn't imply to modify more than a few (let's say 30) lines of code, unless you want to do it yourself.

Quote:
Originally Posted by tauio111

Nice, should be great for shooting auroras.

Yes, also to shoot the night sky. Nice picture by the way!
Quote:
Originally Posted by tauio111

Source is the sourcecode of the apk...
You don't have to flash anything,

Exactly
The Following User Says Thank You to enryea123 For This Useful Post: [ View ] Gift enryea123 Ad-Free
10th December 2016, 03:16 PM |#11  
Senior Member
Thanks Meter: 451
 
Donate to Me
More
Quote:
Originally Posted by enryea123

Thank you for the suggestions! Well I choose a base 60 because it is divisible by 5,4,3,2,1, so I could avoid using "double" values for the exposures and I didn't have to worry about the digit precision, but yes I've modified the code as you suggested to have a better looking exposure time in the app, with some small differences; now it's like 5 s, 4 s, ..., 1/2 s, 1/4.3 s, ... and I've also modified a bit the shorter exposures and added back the 1/60 one.
I've also deleted the line that saves the exposure preference.
I've checked the rotation commit but it is for a newer version of Lcamera, so there are many differences in the code.
Of course any suggestion on how to fix it in my app or how to change the "screen refresh rate" is welcome , as long as it doesn't imply to modify more than a few (let's say 30) lines of code, unless you want to do it yourself.

Looked closer at the commit and you're right, would take a bit of work to implement it in the older version.
I'm not sure but this might be the part that handles the refresh rate of the screen.
Code:
val startPreview =
    for { (cameraOpt, previewSurfaceOpt, previewSessionOpt, autoFocus, focusDistance, autoExposure, iso, exposureTime, metering)
          <- Rx {(this.camera(), this.previewSurface(), this.previewSession(),
                  this.autoFocus(), this.focusDistance(),
                  this.autoExposure(), this.iso(), this.exposureTime(), this.metering())}
Inside that for you could put in an if that checks if this.exposureTime() is less than for example 1/5s, then use a constant of 1/5s instead of this.exposureTime().

I also might have found a way to get the newer version to be able to use slower shutter speeds. The problem I think is this code on line 699.
Code:
val validExposureTimes = Rx { lcamera().toList flatMap { camera => exposureTimes filter { camera.exposureTimeRange contains _ }} }
Which is a list of exposure times the sensor supports. Now, if we set this equal to the var exposureTimes, I think we should be able to use the longer exposure times. I don't know if straight val validExposureTimes = exposureTimes works or if you have to convert the Vector to a List first, haven't programmed in scala before. I would try this out myself if I had a phone to test it on.
The Following User Says Thank You to CazeW For This Useful Post: [ View ] Gift CazeW Ad-Free
Post Reply Subscribe to Thread

Tags
exposure time, nexus 5x, nexus 6p, night, pictures

Guest Quick Reply (no urls or BBcode)
Message:
Previous Thread Next Thread
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes