Find '.dng' image resolution using Python - python-3.x

I am trying to get the '.dng' image resolution but I am getting incorrect resolutions. But I am getting correct resolutions for '.jpg' images
img = Image.open("01109677451NasiLemakBiasa.dng")
width = img.width
height = img.height
print(width, height)
# Output 256 171
The actual resolution of the image (01109677451NasiLemakBiasa.dng) is 1024 x 683
Please help me to get the correct width and height of the image

PIL doesn't read DNG files, nor does it like 16-bit per channel RGB. I think you'll need something like rawpy
import rawpy
path = '/Users/mark/Desktop/RAW_LEICA_M8.DNG'
with rawpy.imread(path) as raw:
rgb = raw.postprocess()
print(rgb.shape) # It's a Numpy array
Sanple Output
Out[9]: (2638, 3920, 3)
Another option is Exiftool, which you can install like this:
pip3 install PyExifTool
and use like this:
import exiftool
with exiftool.ExifTool() as et:
metadata = et.get_metadata('/path/to/RAW_LEICA_M8.DNG')
print(metadata)
{'SourceFile': '/path/to/RAW_LEICA_M8.DNG',
'ExifTool:ExifToolVersion': 12.0,
'File:FileName': 'RAW_LEICA_M8.DNG',
'File:Directory': '/path/to',
'File:FileSize': 10575296,
'File:FileModifyDate': '2021:08:16 08:54:30+01:00',
'File:FileAccessDate': '2021:08:16 09:56:33+01:00',
'File:FileInodeChangeDate': '2021:08:16 09:56:31+01:00',
'File:FilePermissions': 644,
'File:FileType': 'DNG',
'File:FileTypeExtension': 'DNG',
'File:MIMEType': 'image/x-adobe-dng',
'File:ExifByteOrder': 'II',
'EXIF:Make': 'Leica Camera AG',
'EXIF:Model': 'M8 Digital Camera',
'EXIF:Orientation': 1,
'EXIF:Software': 1.107,
'EXIF:Artist': '',
'EXIF:SubfileType': 0,
'EXIF:ImageWidth': 3920, <--- HERE IS THE WIDTH
'EXIF:ImageHeight': 2638, <--- HERE IS THE HEIGHT
'EXIF:BitsPerSample': 8,
'EXIF:Compression': 1,
'EXIF:PhotometricInterpretation': 32803,
'EXIF:StripOffsets': '(Binary data 1315 bytes, use -b option to extract)',
'EXIF:SamplesPerPixel': 1,
'EXIF:RowsPerStrip': 16,
'EXIF:StripByteCounts': '(Binary data 989 bytes, use -b option to extract)',
'EXIF:XResolution': 300,
'EXIF:YResolution': 300,
'EXIF:PlanarConfiguration': 1,
'EXIF:ResolutionUnit': 2,
'EXIF:CFARepeatPatternDim': '2 2',
'EXIF:CFAPattern2': '0 1 1 2',
'EXIF:LinearizationTable': '(Binary data 1244 bytes, use -b option to extract)',
'EXIF:WhiteLevel': 16383,
'EXIF:DefaultCropOrigin': '2 2',
'EXIF:DefaultCropSize': '3916 2634',
'EXIF:BayerGreenSplit': 500,
'EXIF:AntiAliasStrength': 0,
'EXIF:Copyright': '',
'EXIF:ExposureTime': 12,
'EXIF:ExposureProgram': 1,
'EXIF:ISO': 160,
'EXIF:ExifVersion': '0220',
'EXIF:CreateDate': '2007:08:02 22:13:49',
'EXIF:ShutterSpeedValue': 11.3137084989848,
'EXIF:ExposureCompensation': 0,
'EXIF:MaxApertureValue': 2,
'EXIF:MeteringMode': 2,
'EXIF:LightSource': 0,
'EXIF:Flash': 0,
'EXIF:FocalLength': 50,
'EXIF:FileSource': 3,
'EXIF:SceneType': 1,
'EXIF:WhiteBalance': 0,
'EXIF:DigitalZoomRatio': 0,
'EXIF:FocalLengthIn35mmFormat': 67,
'EXIF:SceneCaptureType': 0,
'EXIF:ImageUniqueID': '00000000000000000000000000000147',
'EXIF:SelfTimerMode': 0,
'EXIF:DateTimeOriginal': '2007:08:02 22:13:49',
'EXIF:FocalPlaneXResolution': 3729,
'EXIF:FocalPlaneYResolution': 3764,
'EXIF:FocalPlaneResolutionUnit': 2,
'EXIF:TIFF-EPStandardID': '0 0 0 1',
'EXIF:DNGVersion': '1 0 0 0',
'EXIF:UniqueCameraModel': 'M8 Digital Camera',
'EXIF:ColorMatrix1': '1.0469 -0.5314 0.128 -0.4326 1.2176 0.2419 -0.0886 0.2473 0.716',
'EXIF:ColorMatrix2': '0.7675 -0.2195 -0.0305 -0.586 1.4118 0.1857 -0.2425 0.4007 0.6578',
'EXIF:CameraCalibration1': '1 0 0 0 1 0 0 0 1',
'EXIF:CameraCalibration2': '1 0 0 0 1 0 0 0 1',
'EXIF:AsShotNeutral': '0.4750637903 1 0.7966159382',
'EXIF:BaselineNoise': 1,
'EXIF:BaselineSharpness': 1,
'EXIF:CameraSerialNumber': 3106091,
'EXIF:CalibrationIlluminant1': 17,
'EXIF:CalibrationIlluminant2': 21,
'MakerNotes:UserProfile': 1,
'MakerNotes:SerialNumber': 3106091,
'MakerNotes:WhiteBalance': 0,
'MakerNotes:LensType': '33 3',
'MakerNotes:ExternalSensorBrightnessValue': -5.16796875,
'MakerNotes:MeasuredLV': -4.359375,
'MakerNotes:ApproximateFNumber': 4,
'MakerNotes:CameraTemperature': 19,
'MakerNotes:ColorTemperature': 5515,
'MakerNotes:UV-IRFilterCorrection': 0,
'MakerNotes:CCDVersion': 0,
'MakerNotes:CCDBoardVersion': 1,
'MakerNotes:ControllerBoardVersion': 0,
'MakerNotes:M16CVersion': 0,
'MakerNotes:ImageIDNumber': 327,
'Composite:CFAPattern': '2 2 0 1 1 2',
'Composite:ImageSize': '3920 2638',
'Composite:LensID': '33 3',
'Composite:Megapixels': 10.34096,
'Composite:ScaleFactor35efl': 1.34,
'Composite:ShutterSpeed': 12,
'Composite:CircleOfConfusion': 0.0224225825588557,
'Composite:FOV': 30.0756572109854,
'Composite:FocalLength35efl': 67}
Sample raw images downloaded from Raw Samples.

Related

DataPortal don't correctly read .dat file with few indexed parameters

I'm working with pyomo and need to read data previously wrote in a .dat file.
I'm reading data with following code:
data = DataPortal()
data.load(filename = 'myfilename.dat')
All data is correctly read, except one of my params. This param is defined in my pyomo model as a 3-index param. In my .dat file, this param is wrote as I show (I'll show an example):
param pExample:=
a 0 1 0
a 0 2 0
a 0 3 0
a 1 1 1
a 1 2 1
a 1 3 1
When I read this param with DataPortal, I get the following item in data.items():
pExample = {'a': 1, 1: 1, 2: 1, 3: 1}
It read it as if it would be two dictionaries in two columns each one, while I need something like:
pExample = {('a', 0, 1): 0, ('a', 0, 2): 0, ...}
or maybe like this other one:
pExample = {'a': {0: {1: 0, 2: 0, 3: 0}, 1: {1: 1, 2: 1, 3: 1}}}
Thanks you very much in advance.
==========
Adding reproducible example:
following documentation here
my_data.dat
set I :=
a 1 0
a 0 1
b 2 3;
param B :=
a 1 0 12
a 0 1 4.1
b 2 3 -3.6;
executable:
# data load ex
import pyomo.environ as pyo
m = pyo.AbstractModel()
m.I = pyo.Set(dimen=3)
m.B = pyo.Param(m.I)
data = pyo.DataPortal()
data.load(filename='my_data.dat')
instance = m.create_instance(data)
instance.pprint()
Error:
ERROR: Constructing component 'B' from data={'a': 0, 0: 12, 1: 4.1, 'b': 2, 3:
-3.6} failed:
RuntimeError: Failed to set value for param=B, index=a, value=0.
source error message="Index 'a' is not valid for indexed component 'B'"
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyomo/core/base/param.py", line 915, in construct
self._validate_index(key), val)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyomo/core/base/indexed_component.py", line 571, in _validate_index
raise KeyError(
KeyError: "Index 'a' is not valid for indexed component 'B'"

Calling values from dict to create boolean column in dataframe

Searched multiple threads on here for an answer but nothing is quite like what I am looking to do. I am trying to make a boolean column in a dataframe where one of the parameters is based on metal and associated cost maximum, see Dict below.
Cost_ranges = {'Metals': ["Cu", "Pb", "Zn", "Ni", "Mo", "Co", "Sn", "U3O8", "Ag", "Au", "Pt", "Pd", "Rh", "Os", "Ru", "Ir"],
'Cost Maximum': [350, 200, 200, 500, 800, 1000, 250, 2500, 30, 2500, 500, 1000, 6000, 2500, 2500, 2500]}
The dict is used to complete the below formula:
df_Cost['Total Cost'] >= Cost_ranges['Cost Maximum']
i.e. df_Cost['Metal'] contains to value 'Cu', it calls the 'Cost Maximum' of 350 from the dict and uses this for the boolean expression hence formula would read:
df_Cost[Total Cost] >= 350
I need it to apply to all rows in a dataframe. I have been using df.eval() but need an extra layer of processing to match up the right limit per metal.
I have tried using df.eval(), df.query(), df.loc and df.apply() but keep getting 'TypeError: 'Series' objects are mutable, thus they cannot be hashed' or 'ValueError: ('Lengths must match to compare', (9999,), (16,))' for each solution.
Look forward to the responses.
Depending on your actual data, you could do something like:
import numpy as np
import pandas as pd
Cost_ranges = {'Metals': ["Cu", "Pb", "Zn", "Ni", "Mo", "Co", "Sn", "U3O8", "Ag", "Au", "Pt", "Pd", "Rh", "Os", "Ru", "Ir"],
'Cost Maximum': [350, 200, 200, 500, 800, 1000, 250, 2500, 30, 2500, 500, 1000, 6000, 2500, 2500, 2500]}
N = 20
d = pd.DataFrame({'Metals': np.random.choice(["Cu", "Pb", "Zn", "Ni"], N),
'Cost': np.random.random(N) * 1000})
d.merge(pd.DataFrame(Cost_ranges).astype({'Cost Maximum': float}),
on = "Metals", how = "left")\
.eval('want = Cost > `Cost Maximum`')
# Metals Cost Cost Maximum want
# 0 Cu 297.386007 350.0 False
# 1 Pb 55.570657 200.0 False
# 2 Pb 91.803336 200.0 False
# 3 Cu 916.273995 350.0 True
# 4 Zn 796.383326 200.0 True
# 5 Pb 112.504581 200.0 False
Assuming your df_Cost looks a little like this (with potentially more rows and columns):
>>> df_Cost
Total Cost Metal
0 315 Cu
1 420 Cu
The easiest way is to use a dictionary to translate from Metal to max cost. Then you need to make Cost_ranges into a dictionary mapping metal name to cost:
>>> cost_lookup = dict(zip(Cost_ranges['Metals'], Cost_ranges['Cost Maximum']))
>>> cost_lookup
{'Cu': 350, 'Pb': 200, 'Zn': 200, 'Ni': 500, 'Mo': 800, 'Co': 1000, 'Sn': 250, 'U3O8': 2500, 'Ag': 30, 'Au': 2500, 'Pt': 500, 'Pd': 1000, 'Rh': 6000, 'Os': 2500, 'Ru': 2500, 'Ir': 2500}
>>> df_Cost['Metal'].map(cost_lookup)
0 350
1 350
Name: Metal, dtype: int64
>>> df_Cost['Total Cost'] >= df_Cost['Metal'].map(cost_lookup)
0 False
1 True
dtype: bool

Matplotlib Control Spacing Between Bars

I am trying to insert spacing between two specific bars but cannot find any easy way to do this. I can manually add a dummy row with with 0 height to create and empty space but doesn't give me control of how wide the space should be. Is there a more programmatic method I can use to control the spacing between bars at any position?
Example Code:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
mydict = {
'Event': ['Running', 'Swimming', 'Biking', '', 'Hiking', 'Jogging'],
'Completed': [2, 4, 3, 0, 7, 9],
'Participants': [10, 20, 35, 0, 10, 20]}
df = pd.DataFrame(mydict).set_index('Event')
df = df.assign(Completion=(df.Completed / df.Participants) * 100)
plt.subplots(figsize=(5, 4))
print(df.index)
ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')
plt.xticks(rotation=60)
plt.tight_layout()
plt.show()
Example DataFrame Output:
Completed Participants Completion
Event
Running 2 10 20.000000
Swimming 4 20 20.000000
Biking 3 35 8.571429
0 0 NaN
Hiking 7 10 70.000000
Jogging 9 20 45.000000
Example output (blue arrows added outside of code to show where empty row was added.):
I think you can access the position of the boxes and the name of the labels. Then modify them. You may find an more general way depending on your use case, but this works for the given example.
#define a function to add space starting a specific label
def add_space_after(ax, label_shift='', extra_space=0):
bool_space = False
# get postion of current ticks
ticks_position = np.array(ax.get_yticks()).astype(float)
# iterate over the boxes/label
for i, (patch, label) in enumerate(zip(ax.patches, ax.get_yticklabels())):
# if the label to start the shift found
if label.get_text()==label_shift: bool_space = True
# reposition the boxes and the labels afterward
if bool_space:
patch.set_y(patch.get_y() + extra_space)
ticks_position[i] += extra_space
# in the case where the spacing is needed
if bool_space:
ax.set_yticks(ticks_position)
ax.set_ylim([ax.get_ylim()[0]+extra_space, ax.get_ylim()[1]])
#note: no more blank row
mydict = {
'Event': ['Running', 'Swimming', 'Biking', 'Hiking', 'Jogging'],
'Completed': [2, 4, 3, 7, 9],
'Participants': [10, 20, 35, 10, 20]}
df = pd.DataFrame(mydict).set_index('Event')
df = df.assign(Completion=(df.Completed / df.Participants) * 100)
ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')
plt.xticks(rotation=60)
plt.tight_layout()
#use the function
add_space_after(ax, 'Hiking', 0.6)
plt.show()

Python - How to process nested dictionaries written as strings in a Dataframe?

I'm running into a problem which I found similar to other examples on the plateform but not quite the same.
My dataframe is based on a CSV of sensor data.
Here is the output of only one cell :
df['streams'][0]
out :
> "{'AirBeam-PM': {'session_id': 83611, 'measurements_count': 1904,
> 'unit_name': 'micrograms per cubic meter', 'sensor_name':
> 'AirBeam-PM', 'threshold_medium': 35, 'size': 1904, 'max_longitude':
> 105.8774276, 'sensor_package_name': 'AirBeam:00189610582E', 'unit_symbol': 'µg/m³', 'measurement_short_type': 'PM',
> 'average_value': 23.6113, 'start_longitude': 105.8773687,
> 'threshold_very_high': 150, 'min_latitude': 21.014873333,
> 'threshold_very_low': 0, 'measurement_type': 'Particulate Matter',
> 'threshold_high': 55, 'start_latitude': 21.0243842, 'min_longitude':
> 105.854333333, 'max_latitude': 21.040161667, 'id': 292691, 'threshold_low': 12}, 'AirBeam-RH': {'session_id': 83611,
> 'measurements_count': 1904, 'unit_name': 'percent', 'sensor_name':
> 'AirBeam-RH', 'threshold_medium': 50, 'size': 1904, 'max_longitude':
> 105.8774276, 'sensor_package_name': 'AirBeam:00189610582E', 'unit_symbol': '%', 'measurement_short_type': 'RH', 'average_value':
> 52.0557, 'start_longitude': 105.8773687, 'threshold_very_high': 100, 'min_latitude': 21.014873333, 'threshold_very_low': 0,
> 'measurement_type': 'Humidity', 'threshold_high': 75,
> 'start_latitude': 21.0243842, 'min_longitude': 105.854333333,
> 'max_latitude': 21.040161667, 'id': 292690, 'threshold_low': 25},
> 'AirBeam-F': {'session_id': 83611, 'measurements_count': 1904,
> 'unit_name': 'degrees Fahrenheit', 'sensor_name': 'AirBeam-F',
> 'threshold_medium': 50, 'size': 1904, 'max_longitude': 105.8774276,
> 'sensor_package_name': 'AirBeam:00189610582E', 'unit_symbol': 'F',
> 'measurement_short_type': 'F', 'average_value': 83.7983,
> 'start_longitude': 105.8773687, 'threshold_very_high': 100,
> 'min_latitude': 21.014873333, 'threshold_very_low': 0,
> 'measurement_type': 'Temperature', 'threshold_high': 75,
> 'start_latitude': 21.0243842, 'min_longitude': 105.854333333,
> 'max_latitude': 21.040161667, 'id': 292692, 'threshold_low': 25}}"
As you can see, there is a larger dictionary encompassing different dictionaries but it's all written as a massive string which means I can't use any of the usual dict keys and I don't know what to make of it.
The end goal would be to have a dataframe created from the output of each cell, that is each dict in the pandas Series written in a dataframe.
Can anyone help me?
Thanks

Tkinter (python3) How to insert text vertically in Text widget?

i have create a botton with Tkinter, like this:
self.calc_amm = Button(self.window)
self.calc_amm["text"] = "Calcola"
self.calc_amm["command"] = lambda: self.testo.insert(1.0, (operazioni.ammortamento(var_sel.get(), self.inserisci_imponibile.get(), self.inserisci_tasso.get(), var_periodo.get(), self.durata.get())))
self.calc_amm.grid(row = 6, column = 0, padx = 2, pady = 2)
where
self.calc_amm["command"] = lambda: self.**testo**.insert(1.0, (operazioni.ammortamento(var_sel.get(), self.inserisci_imponibile.get(), self.inserisci_tasso.get(), var_periodo.get(), self.durata.get())))
"testo" is
self.testo = Text(f)
self.testo["background"] = "white"
self.testo.grid(row = 4, column = 0, columnspan = 4)
The idea is get the value var_sel.get(), self.inserisci_imponibile.get(), self.inserisci_tasso.get(), var_periodo.get(), self.durata.get() and pass the values to the function operazioni.ammortamento(a,b,c,d,e).
In the function operazioni.ammortamento(a,b,c,d,e) i do some calculations, and return 3 lists (return(arr_rata, arr_quota_cap, arr_cap_res)).
My output, in the Text widget, is as follows:
{1 2 3 4 5 6 7 8 9 10} {5000 5000 5000 5000 5000 5000 5000 5000 5000 5000} {4500 4000 3500 3000 2500 2000 1500 1000 500 0}
How can I do to have the output like as follows???
Something: Someth.: Someth.:
{1 5000 4500
2 5000 4000
3 5000 3500
4 5000 3000
5 5000 2500
6 5000 2000
7 5000 1500
8 5000 1000
9 5000 500
10} 5000 0
Thank you so much!!
First make it work, then make it beautiful; You have three lists:
arr_rata = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
arr_quota_cap = [5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000]
arr_cap_res = [4500, 4000, 3500, 3000, 2500, 2000, 1500, 1000, 500, 0]
Making a Text widget as an example:
from tkinter import *
root = Tk()
testo = Text(root, width=40, height=15)
testo.grid(padx=10, pady=10, sticky='nsew')
Print them to Text widget one index at a time:
testo.delete(1.0,END) # Delete text from widget if there is any
testo.insert(END,'rata: quota_cap: cap_res:\n')
for index in range(len(arr_rata)):
col1 = '{:<8}'.format(arr_rata[index])
col2 = '{:<13}'.format(arr_quota_cap[index])
col3 = '{}'.format(arr_cap_res[index])
line = col1 + col2 + col3 + '\n'
testo.insert(END,line)
You can rewrite it with list comprehension or lambda later if you think it's necessary.
Also see The Tkinter Text Widget

Resources