What is "35mm equivalent focal length?"

本文解释了35mm相机中的35mm含义及其与镜头焦距的关系,介绍了正常镜头的概念,并探讨了数字相机如何通过参考35mm相机的焦距来描述其镜头。


What does the 35mm mean in "35mm Camera"?

Let's get something out of the way.  Lots of things on a camera are measured in millimeters.  For 35mm cameras, there are two measurements that are sometimes confused with the focal length.

First, the 35 in "35mm camera" doesn't refer to the focal length or even to the size of the image on the film.  It is the width of the film including the sprockets.  35mm film is more properly called 135 format film and has these dimensions:

film.gif (2451 bytes)

It can be confusing when a 35mm camera is described as having a 35mm lens.  Does this mean that the lens has a 35mm focal length (very possible) or that the writer is being specific about the camera, not the lens?  Sometimes it's hard to be sure.

The second measurement that is sometimes confused with the focal length is the diameter of the filter ring.  This is the threaded ring on the front of the lens barrel that accepts  Filter rings come in various sizes like 49mm, 52mm, 58mm.  This size is dictated by the diameter of the lens barrel and is independent of the lens focal length.


What makes a lens "normal"?

A "normal" lens produces a field of view that is similar to human vision.  The diagonal of the image plane is typically used as the reference for field of view determination.  A "normal" lens has a focal length that is approximately equal to the diagonal measurement of the image plane.  When the focal length is equal to the diagonal measurement it produces a diagonal field of view of approximately 53 deg which is similar to human vision.

For 35mm film (24mm by 36mm), the diagonal measurement is 43.27mm.   50mm is close to this measurement so it is considered a "normal" lens.  A 50mm lens produces a 47 deg diagonal field of view which is close to 53 deg.


What about digital cameras?

The CCD arrays on digital cameras are typically much smaller than the imaging area of 35mm film.  This means that the focal length that produces a "normal" field of view is much smaller than 50mm.

Unlike 35mm film which is the same regardless of what camera you use, the size of the CCD array varies from camera to camera.  This poses a problem.  You cannot know whether a focal length is "normal", wide angle or telephoto without knowing the exact size of the CCD array.  Unfortunately, even knowing the exact size of the CCD array may not help because sometimes the imaging area doesn't even cover the entire array!

Because many people are familiar with focal lengths of lenses for 35mm cameras, the digital camera manufacturers choose to describe the focal length of their cameras by reference to the focal length that would produce a similar field of view on a 35mm camera.

Consider, for example, a digital camera with a CCD array measuring 8.10mm by 6.08mm.  The diagonal measurement of this CCD array would be 10.13mm.  A lens with a focal length of 11.7mm would produce a diagonal field of view of 47deg, the same as a 50mm lens on a camera.  So for this camera, an 11.7mm lens would be described as having a 35mm equivalent focal length of 50mm.

By describing the lenses this way, the digital camera companies appeal to users' familiarity with 35mm camera equipment.

[from What is "35mm equivalent focal length?"  http://www.panoramafactory.com/equiv35/equiv35.html#What makes a lens "normal" ]

焦距(相当于35mm相机)是什么?

目前数码相机的成像器件面积都小于普通的135胶卷(即35mm胶卷相机)的面积,所以同样的视角时其镜头焦距相对于35MM相机要短,说到其镜头焦距时常不会涉及到其实际的物理焦距,而说与其视角相当的35mm(国内的135)相机的镜头焦距,也就是说,其“镜头的视角相当于XX”。 35mm胶片的尺寸是36 x 24mm,也就是我们平时在照相机馆中看到的最为普遍的那种胶卷,由于35mm焦长的广泛使用,因此它成为了一种标尺,就像我们用米或者公斤来度衡长度和重量一样,35mm成为我们判断镜头视野度的一种标注。例如,28mm 焦长可以实现广角拍摄,35mm焦长就是标准视角,50mm镜头是最接近人眼自然视角的,而380mm镜头就属于超望远视角,可捕捉远方的景物。


以下代码中,输出的航向角yaw与实际绘制的动图中的航向角相反,是哪一本代码出现了问题? %% 1. 场景创建 scenario = drivingScenario('SampleTime', 0.1, 'StopTime', 30); roadCenters = [0 0 0; 50 0 0; 100 20 0; 200 40 0; 250 50 0; 300 40 0]; road(scenario, roadCenters, 'Lanes', lanespec(3)); % 添加车辆 vehicles = [... vehicle(scenario, 'ClassID', 1, 'Position', [0 0 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4),... vehicle(scenario, 'ClassID', 1, 'Position', [40 0 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4),... vehicle(scenario, 'ClassID', 1, 'Position', [60 0 0], 'Length', 4.7, 'Width', 1.8, 'Height', 1.4)... ]; egoVehicle = vehicles(1); sideVehicle_1=vehicles(2); sideVehicle_2=vehicles(3); %设置主车轨迹sideVehicle1=vehicles(2);sideVehicle1=vehicles(2); trajectoryPoints = [... 0 0 0; 50 0 0; 100 20 0; 200 40 0; 250 50 0; 300 40 0]; speedProfile = [10, 12, 15, 18, 15,10]; % 分段速度(m/s) trajectory(egoVehicle, trajectoryPoints, speedProfile); %% 2. 数据采集 - 优化初始化 % 预分配存储空间 totalFrames = round(scenario.StopTime/scenario.SampleTime); cameraFrames = cell(totalFrames, 1); vehiclePoses = zeros(totalFrames, 3); % 初始化图形系统 [hFig, hAx, actorPlots] = initializeGraphics(); setappdata(hFig, 'GraphicsActive', true); %% 3. 场景渲染循环 - 增强健壮性 frameCount = 0; while advance(scenario) && frameCount < totalFrames frameCount = frameCount + 1; % 获取车辆位姿 position = egoVehicle.Position(1:2); yaw = egoVehicle.Yaw; vehiclePoses(frameCount, :) = [position, yaw]; % ==== 修复后的图形处理代码 ==== % 检查图形系统是否激活 if ishghandle(hFig) && isvalid(hFig) && getappdata(hFig, 'GraphicsActive') % 安全更新图形 try updateRoadGraphics(scenario, hAx); actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx); catch ME warning('图形更新错误:',' %s', ME.message); [hFig, hAx, actorPlots] = initializeGraphics(); setappdata(hFig, 'GraphicsActive', true); end % 动态调整视图范围 if ishghandle(hAx) && isvalid(hAx) set(hAx, 'XLim', [position(1)-20, position(1)+50], ... 'YLim', [position(2)-10, position(2)+10]); end % 安全帧捕获 if mod(frameCount, 5) == 0 try cameraFrames{frameCount} = safeCaptureFrame(hFig); if ~isempty(cameraFrames{frameCount}) showFrameInSeparateWindow(cameraFrames{frameCount}, frameCount, totalFrames, position, yaw); end catch ME warning('帧捕获失败:',' %s', ME.message); cameraFrames{frameCount} = []; end else cameraFrames{frameCount} = []; end else cameraFrames{frameCount} = []; end % ==== 修复结束 ==== end % 资源清理 if ishandle(hFig) close(hFig); end fprintf('数据采集完成: 共 %d 帧\n', frameCount); %% 4. 相机配置与鸟瞰图生成 % 相机内参设置 focalLength = [1000, 1000]; % 焦距 [fx, fy] principalPoint = [320, 240]; % 主点 [cx, cy] imageSize = [480, 640]; % 图像尺寸 [高度, 宽度] % 相机安装参数 height = 1.5; % 离地高度 (米) pitch = 5; % 俯仰角 (度) % 创建相机内参对象 camIntrinsics = cameraIntrinsics(focalLength, principalPoint, imageSize); % 创建 monoCamera 对象 sensor = monoCamera(camIntrinsics, height, 'Pitch', pitch); % 定义鸟瞰图输出范围 [xmin, xmax, ymin, ymax] outView = [-5, 50, -5, 5]; % X: -5到50米, Y: -5到5米 % 定义鸟瞰图输出尺寸 [高度, 宽度] outImageSize = [600, 800]; % 高度600像素, 宽度800像素 % 创建 birdsEyeView 对象 birdsEyeConfig = birdsEyeView(sensor, outView, outImageSize); % 车道线检测参数 laneDetectionParams = struct(... 'Sensitivity', 0.85, ... 'LaneWidthRange', [2.5 4.5], ... 'MaxNumLanes', 3, ... 'ROI', [1 400; 1 720; 1280 720; 1280 400]); % 初始化鸟瞰图显示 figure('Name', '车道线鸟瞰图', 'Position', [100 100 1200 600]) hAxes = axes; hold(hAxes, 'on'); axis(hAxes, 'equal'); grid(hAxes, 'on'); xlabel('X (m)'); ylabel('Y (m)'); title('实时车道线检测与车辆轨迹'); % 处理每一帧图像 for frameIdx = 1:min(100, frameCount) % 获取当前帧 I = cameraFrames{frameIdx}; if isempty(I) continue; end % 车道线检测 [laneBoundaries, valid] = detectLanes(I, laneDetectionParams); if valid % 转换为鸟瞰图 birdsEyeImage = transformImage(birdsEyeConfig, I); % 显示鸟瞰图 imshow(birdsEyeImage, 'Parent', hAxes); title(hAxes, sprintf('帧 %d/%d | 检测到 %d 条车道线', frameIdx, frameCount, numel(laneBoundaries))); % 绘制检测到的车道线 colors = ['r', 'g', 'b', 'c']; for laneIdx = 1:numel(laneBoundaries) lanePoints = laneBoundaries(laneIdx).Points; lanePointsVehicle = imageToVehicle(birdsEyeConfig, lanePoints); plot(hAxes, lanePointsVehicle(:,1), lanePointsVehicle(:,2), ... [colors(laneIdx) '-'], 'LineWidth', 2); end % 绘制车辆位置 vehiclePos = vehiclePoses(frameIdx, 1:2); yaw = vehiclePoses(frameIdx, 3); plot(hAxes, vehiclePos(1), vehiclePos(2), 'yo', ... 'MarkerSize', 10, 'MarkerFaceColor', 'y'); % 绘制车辆方向箭头 arrowLength = 3; endX = vehiclePos(1) + arrowLength * cosd(yaw); endY = vehiclePos(2) + arrowLength * sind(yaw); quiver(hAxes, vehiclePos(1), vehiclePos(2), ... endX-vehiclePos(1), endY-vehiclePos(2), ... 0, 'Color', 'y', 'LineWidth', 2, 'MaxHeadSize', 2); % 绘制轨迹线 if frameIdx > 1 plot(hAxes, vehiclePoses(1:frameIdx,1), vehiclePoses(1:frameIdx,2), ... 'g-', 'LineWidth', 2); end % 添加图例 legendEntries = arrayfun(@(x) sprintf('车道 %d', x), 1:numel(laneBoundaries), 'UniformOutput', false); legendEntries = [legendEntries, '车辆位置', '行驶方向', '行驶轨迹']; legend(hAxes, legendEntries, 'Location', 'northeastoutside'); drawnow; end end %% 5. 完整车道线地图构建(修复属性访问问题) % 使用正确的属性名称 ImageSize bevSize = birdsEyeConfig.ImageSize; % ✅ 修复属性名称 finalMap = uint8(zeros(bevSize)); % ✅ 使用正确的尺寸 laneMaps = cell(1, 3); % 初始化车道掩码 for i = 1:3 laneMaps{i} = false(bevSize(1:2)); % ✅ 使用正确的尺寸 end % 累积所有车道线信息 for frameIdx = 1:frameCount I = cameraFrames{frameIdx}; if isempty(I) continue; end [laneBoundaries, valid] = detectLanes(I, laneDetectionParams); if valid for laneIdx = 1:min(numel(laneBoundaries), 3) lanePoints = laneBoundaries(laneIdx).Points; lanePointsVehicle = imageToVehicle(birdsEyeConfig, lanePoints); lanePixels = vehicleToImage(birdsEyeConfig, lanePointsVehicle); % 创建车道线掩码 laneMask = false(bevSize(1:2)); % ✅ 使用正确的尺寸 for j = 1:size(lanePixels, 1) x = round(lanePixels(j, 1)); y = round(lanePixels(j, 2)); if x >= 1 && x <= bevSize(2) && y >= 1 && y <= bevSize(1) laneMask(y, x) = true; end end % 膨胀处理 se = strel('disk', 3); laneMask = imdilate(laneMask, se); laneMaps{laneIdx} = laneMaps{laneIdx} | laneMask; end end end % 创建彩色地图 colorMap = repmat(finalMap, [1 1 3]); colors = uint8([255 0 0; 0 255 0; 0 0 255]); % 红、绿、蓝 for laneIdx = 1:3 mask = laneMaps{laneIdx}; for c = 1:3 channel = colorMap(:, :, c); channel(mask) = colors(laneIdx, c); colorMap(:, :, c) = channel; end end % 添加车辆轨迹 trajectoryPixels = vehicleToImage(birdsEyeConfig, vehiclePoses(:, 1:2)); trajectoryPixels = round(trajectoryPixels); for i = 1:size(trajectoryPixels, 1) x = trajectoryPixels(i, 1); y = trajectoryPixels(i, 2); if x >= 1 && x <= bevSize(2) && y >= 1 && y <= bevSize(1) colorMap(y-2:y+2, x-2:x+2, 1) = 255; % R colorMap(y-2:y+2, x-2:x+2, 2) = 255; % G colorMap(y-2:y+2, x-2:x+2, 3) = 0; % B end end % 显示最终鸟瞰地图 figure('Name', '完整车道线鸟瞰图', 'Position', [100 100 1000 800]) imshow(colorMap) title('车道线鸟瞰图 (红色: 左车道, 绿色: 中车道, 蓝色: 右车道)'); hold on; text(50, 50, '↑ 行驶方向', 'Color', 'w', 'FontSize', 14, 'FontWeight', 'bold'); %% ================ 关键辅助函数 ================ function [hFig, hAx, actorPlots] = initializeGraphics() hFig = figure('Position', [100, 100, 1280, 720], 'Name', '场景预览', ... 'CloseRequestFcn', @closeFigureCallback, ... 'Tag', 'DrivingSimFigure', ... 'Visible', 'on'); hAx = axes('Parent', hFig); axis(hAx, 'equal'); hold(hAx, 'on'); grid(hAx, 'on'); xlabel(hAx, 'X (m)'); ylabel(hAx, 'Y (m)'); title(hAx, '驾驶场景预览'); set(hAx, 'Tag', 'DrivingSimAxes'); actorPlots = gobjects(0); updateRoadGraphics([], hAx); function closeFigureCallback(~,~) setappdata(hFig, 'GraphicsActive', false); delete(hFig); end end function updateRoadGraphics(scenario, hAx) roadBorderPlot = findobj(hAx, 'Tag', 'RoadBorderPlot'); if isempty(roadBorderPlot) || ~isgraphics(roadBorderPlot) || ~isvalid(roadBorderPlot) roadBorderPlot = plot(hAx, NaN, NaN, 'k-', 'LineWidth', 2); set(roadBorderPlot, 'Tag', 'RoadBorderPlot'); end if ~isempty(scenario) && isgraphics(hAx) && isvalid(hAx) roadBorders = roadBoundaries(scenario); allX = []; allY = []; for i = 1:numel(roadBorders) border = roadBorders{i}; allX = [allX; border(:,1); NaN]; allY = [allY; border(:,2); NaN]; end if isgraphics(roadBorderPlot) && isvalid(roadBorderPlot) set(roadBorderPlot, 'XData', allX, 'YData', allY); else roadBorderPlot = plot(hAx, allX, allY, 'k-', 'LineWidth', 2); set(roadBorderPlot, 'Tag', 'RoadBorderPlot'); end end end function actorPlots = updateVehicleGraphics(vehicles, actorPlots, hAx) if ~isgraphics(hAx) || ~isvalid(hAx) return; end if isempty(actorPlots) || numel(actorPlots) < numel(vehicles) actorPlots = gobjects(numel(vehicles), 1); end for i = 1:numel(vehicles) if i <= numel(actorPlots) && isgraphics(actorPlots(i)) && isvalid(actorPlots(i)) else actorPlots(i) = patch(hAx, 'Vertices', [], 'Faces', 1:4, ... 'FaceColor', 'b', 'EdgeColor', 'k', ... 'Tag', sprintf('VehiclePatch%d', i)); end actor = vehicles(i); pos = actor.Position(1:2); yaw = actor.Yaw; len = actor.Length; wid = actor.Width; corners = [ -len/2, -wid/2; len/2, -wid/2; len/2, wid/2; -len/2, wid/2; ]; rotMat = [cosd(yaw) -sind(yaw); sind(yaw) cosd(yaw)]; corners = corners * rotMat; corners(:,1) = corners(:,1) + pos(1); corners(:,2) = corners(:,2) + pos(2); if isgraphics(actorPlots(i)) && isvalid(actorPlots(i)) set(actorPlots(i), 'Vertices', corners); else actorPlots(i) = patch(hAx, corners(:,1), corners(:,2), 'b', ... 'Tag', sprintf('VehiclePatch%d', i)); end end end function frame = safeCaptureFrame(hFig) frame = []; if ~isgraphics(hFig) || ~isvalid(hFig) return; end try tmpFile = [tempname '.png']; print(hFig, '-dpng', '-r0', tmpFile); frame = imread(tmpFile); delete(tmpFile); return; catch end try oldVer = get(hFig, 'Renderer'); set(hFig, 'Renderer', 'painters'); frame = hardcopy(hFig, '-dzbuffer', '-r0'); set(hFig, 'Renderer', oldVer); return; catch end warning('安全捕获方法失败,返回空帧'); end function showFrameInSeparateWindow(frame, frameCount, totalFrames, position, yaw) persistent frameFig if isempty(frameFig) || ~isvalid(frameFig) frameFig = figure('Name', '帧预览', 'NumberTitle', 'off', ... 'Position', [200, 200, 800, 600]); else figure(frameFig); end imshow(frame); title(sprintf('帧 %d/%d | X=%.1fm Y=%.1fm Yaw=%.1f°', ... frameCount, totalFrames, position(1), position(2), yaw)); drawnow limitrate; end %% 辅助函数:车道线检测 function [laneBoundaries, valid] = detectLanes(I, params) hsv = rgb2hsv(I); saturation = hsv(:, :, 2); enhanced = imadjust(saturation); roiMask = poly2mask(params.ROI(:,1), params.ROI(:,2), size(I,1), size(I,2)); enhanced(~roiMask) = 0; edges = edge(enhanced, 'Canny', [0.1 0.3]); [H, T, R] = hough(edges, 'Theta', -30:0.5:30); P = houghpeaks(H, 10, 'Threshold', 0.2*max(H(:))); lines = houghlines(edges, T, R, P, 'FillGap', 100, 'MinLength', 50); validLanes = struct('Points', {}, 'Strength', {}); for k = 1:length(lines) xy = [lines(k).point1; lines(k).point2]; lineLength = norm(xy(1,:) - xy(2,:)); angle = atan2d(xy(2,2)-xy(1,2), xy(2,1)-xy(1,1)); if abs(angle) < 10 || abs(angle) > 170 continue; end lane.Points = interpolateLine(xy(1,:), xy(2,:), 50); lane.Strength = lineLength; validLanes(end+1) = lane; end if numel(validLanes) < 2 laneBoundaries = []; valid = false; return; end yMeans = arrayfun(@(x) mean(x.Points(:,2)), validLanes); [~, sortedIdx] = sort(yMeans, 'descend'); validLanes = validLanes(sortedIdx); laneBoundaries = validLanes(1:min(numel(validLanes), params.MaxNumLanes)); valid = true; end %% 辅助函数:线段插值 function points = interpolateLine(p1, p2, numPoints) x = linspace(p1(1), p2(1), numPoints); y = linspace(p1(2), p2(2), numPoints); points = [x' y']; end
07-16
[Serializable] public class EXIF { #region -- Class level members -- // Class level members. private Image _picture; #endregion #region -- Constructors -- // Constructors. /// <summary> /// This is default constructor of the EXIF class. /// </summary> public EXIF() { } /// <summary> /// This is base constructor of the EXIF class. /// </summary> public EXIF(string filePath) { _picture = Image.FromFile(filePath); } #endregion #region -- Public methods -- /// <summary> /// This method returns EXIF property values. /// </summary> /// <param name="exifCode">EXIF property to be returned.</param> public string GetEXIFProperty(Definitions.exifCode exifCode) { // Declare local variables. string returnValue; try { // All of the EXIF properties will return strings to display in the control. // Some of the properties require additional formatting or massaging // of the data once it is returned. Those properties have their own // methods. switch (exifCode) { case Definitions.exifCode.ImageDescription: returnValue = ParsedString(Definitions.exifCode.ImageDescription); break; case Definitions.exifCode.Make: returnValue = ParsedString(Definitions.exifCode.Make); break; case Definitions.exifCode.Model: returnValue = ParsedString(Definitions.exifCode.Model); break; case Definitions.exifCode.Orientation: returnValue = Orientation(); break; case Definitions.exifCode.XResolution: returnValue = ParseResolution(Definitions.exifCode.XResolution); break; case Definitions.exifCode.YResolution: returnValue = ParseResolution(Definitions.exifCode.YResolution); break; case Definitions.exifCode.ResolutionUnit: returnValue = ResolutionUnit(); break; case Definitions.exifCode.Software: returnValue = ParsedString(Definitions.exifCode.Software); break; case Definitions.exifCode.DateTime: returnValue = ParsedDate(Definitions.exifCode.DateTime).ToString(); break; case Definitions.exifCode.WhitePoint: returnValue = WhitePoint(); break; case Definitions.exifCode.PrimaryChromaticities: returnValue = PrimaryChromaticities(); break; case Definitions.exifCode.YCbCrCoefficients: returnValue = YCbCrCoefficients(); break; case Definitions.exifCode.YCbCrPositioning: returnValue = YCbCrPositioning(); break; case Definitions.exifCode.ReferenceBlackWhite: returnValue = ReferenceBlackWhite(); break; case Definitions.exifCode.Copyright: returnValue = ParsedString(Definitions.exifCode.Copyright); break; case Definitions.exifCode.ExposureTime: returnValue = ExposureTime(); break; case Definitions.exifCode.FNumber: returnValue = FNumber(); break; case Definitions.exifCode.ExposureProgram: returnValue = ExposureProgram(); break; case Definitions.exifCode.ISOSpeedRatings: returnValue = UnformattedShort(Definitions.exifCode.ISOSpeedRatings); break; case Definitions.exifCode.ExifVersion: returnValue = ParsedString(Definitions.exifCode.ExifVersion); break; case Definitions.exifCode.DateTimeOriginal: returnValue = ParsedDate(Definitions.exifCode.DateTimeOriginal).ToString(); break; case Definitions.exifCode.DateTimeDigitized: returnValue = ParsedDate(Definitions.exifCode.DateTimeDigitized).ToString(); break; case Definitions.exifCode.ComponentsConfiguration: returnValue = ComponentsConfiguration(); break; case Definitions.exifCode.CompressedBitsPerPixel: returnValue = CompressedBitsPerPixel(); break; case Definitions.exifCode.ShutterSpeedValue: returnValue = ShutterSpeedValue(); break; case Definitions.exifCode.ApertureValue: returnValue = ApertureValue(); break; case Definitions.exifCode.BrightnessValue: returnValue = BrightnessValue(); break; case Definitions.exifCode.ExposureBiasValue: returnValue = ExposureBiasValue(); break; case Definitions.exifCode.MaxApertureValue: returnValue = MaxApertureValue(); break; case Definitions.exifCode.SubjectDistance: returnValue = SubjectDistance(); break; case Definitions.exifCode.MeteringMode: returnValue = MeteringMode(); break; case Definitions.exifCode.LightSource: returnValue = LightSource(); break; case Definitions.exifCode.Flash: returnValue = Flash(); break; case Definitions.exifCode.FocalLength: returnValue = FocalLength(); break; case Definitions.exifCode.MakerNote: returnValue = MakerNote(); break; case Definitions.exifCode.UserComment: returnValue = ParsedString(Definitions.exifCode.UserComment); break; case Definitions.exifCode.SubsecTime: returnValue = ParsedString(Definitions.exifCode.SubsecTime); break; case Definitions.exifCode.SubsecTimeOriginal: returnValue = ParsedString(Definitions.exifCode.SubsecTimeOriginal); break; case Definitions.exifCode.SubsecTimeDigitized: returnValue = ParsedString(Definitions.exifCode.SubsecTimeDigitized); break; case Definitions.exifCode.FlashpixVersion: returnValue = ParsedString(Definitions.exifCode.FlashpixVersion); break; case Definitions.exifCode.ColorSpace: returnValue = ColorSpace(); break; case Definitions.exifCode.RelatedSoundFile: returnValue = ParsedString(Definitions.exifCode.RelatedSoundFile); break; case Definitions.exifCode.FocalPlaneXResolution: returnValue = FocalPlaneXResolution(); break; case Definitions.exifCode.FocalPlaneYResolution: returnValue = FocalPlaneYResolution(); break; case Definitions.exifCode.FocalPlaneResolutionUnit: returnValue = ResolutionUnit(); break; case Definitions.exifCode.ExposureIndex: returnValue = ExposureIndex(); break; case Definitions.exifCode.SensingMethod: returnValue = SensingMethod(); break; case Definitions.exifCode.FileSource: returnValue = FileSource(); break; case Definitions.exifCode.SceneType: returnValue = SceneType(); break; case Definitions.exifCode.CFAPattern: returnValue = ParsedString(Definitions.exifCode.CFAPattern); break; case Definitions.exifCode.InteroperabilityIndex: returnValue = ParsedString(Definitions.exifCode.InteroperabilityIndex); break; case Definitions.exifCode.ImageWidth: returnValue = UnformattedShort(Definitions.exifCode.ImageWidth); break; case Definitions.exifCode.ImageLength: returnValue = UnformattedShort(Definitions.exifCode.ImageLength); ; break; case Definitions.exifCode.BitsPerSample: returnValue = BitsPerSample(); break; case Definitions.exifCode.Compression: returnValue = Compression(); break; case Definitions.exifCode.PhotometricInterpretation: returnValue = PhotometricInterpretation(); break; case Definitions.exifCode.StripOffsets: returnValue = StripOffsets(); break; case Definitions.exifCode.SamplesPerPixel: returnValue = UnformattedShort(Definitions.exifCode.SamplesPerPixel); break; case Definitions.exifCode.RowsPerStrip: returnValue = UnformattedShort(Definitions.exifCode.RowsPerStrip); break; case Definitions.exifCode.StripByteCounts: returnValue = StripByteCounts(); break; case Definitions.exifCode.PlanarConfiguration: returnValue = PlanarConfiguration(); break; case Definitions.exifCode.YCbCrSubSampling: returnValue = YCbCrSubSampling(); break; case Definitions.exifCode.ImageUniqueID: returnValue = ParsedString(Definitions.exifCode.ImageUniqueID); break; case Definitions.exifCode.JPEGInterchangeFormatLength: returnValue = UnformattedShort(Definitions.exifCode.JPEGInterchangeFormatLength); break; case Definitions.exifCode.TransferFunction: returnValue = "Not implemented."; break; case Definitions.exifCode.PixelXDimension: returnValue = UnformattedShort(Definitions.exifCode.PixelXDimension); break; case Definitions.exifCode.PixelYDimension: returnValue = UnformattedShort(Definitions.exifCode.PixelYDimension); break; case Definitions.exifCode.SpectralSensitivity: returnValue = ParsedString(Definitions.exifCode.SpectralSensitivity); break; case Definitions.exifCode.OECF: returnValue = ParsedString(Definitions.exifCode.OECF); break; case Definitions.exifCode.CustomRendered: returnValue = CustomRendered(); break; case Definitions.exifCode.ExposureMode: returnValue = ExposureMode(); break; case Definitions.exifCode.WhiteBalance: returnValue = WhiteBalance(); break; case Definitions.exifCode.DigitalZoomRatio: returnValue = DigitalZoomRatio(); break; case Definitions.exifCode.FocalLengthIn35mmFilm: returnValue = FocalLengthIn35mmFilm(); break; case Definitions.exifCode.SceneCaptureType: returnValue = SceneCaptureType(); break; case Definitions.exifCode.GainControl: returnValue = GainControl(); break; case Definitions.exifCode.Contrast: returnValue = Contrast(); break; case Definitions.exifCode.Saturation: returnValue = Saturation(); break; case Definitions.exifCode.Sharpness: returnValue = Sharpness(); break; case Definitions.exifCode.DeviceSettingDescription: returnValue = ParsedString(Definitions.exifCode.DeviceSettingDescription); break; case Definitions.exifCode.SubjectDistanceRange: returnValue = SubjectDistanceRange(); break; default: returnValue = "EXIF property not found."; break; } return returnValue; } catch { return "N/A"; } } #endregion #region -- EXIF Methods -- /// <summary> /// This method returns the bits per sample EXIF property. /// </summary> private string BitsPerSample() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.BitsPerSample); //Translate the EXIF code into a readable value. if (!data.Equals(null)) { returnValue = data[0].ToString() + " " + data[1].ToString() + " " + data[2].ToString(); } return returnValue; } /// <summary> /// This method returns the compression EXIF property. /// </summary> private string Compression() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.Compression); //Translate the EXIF code into a readable value. if (!data.Equals(null)) { switch (data[0]) { case 1: returnValue = "uncompressed"; break; case 6: returnValue = "JPEG compression (thumbnails only)"; break; default: returnValue = "reserved"; break; } } return returnValue; } /// <summary> /// This method returns the photometric interpretation EXIF property. /// </summary> private string PhotometricInterpretation() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.PhotometricInterpretation); //Translate the EXIF code into a readable value. if (data != null) { switch (data[0]) { case 2: returnValue = "RBG"; break; case 6: returnValue = "YCbCr"; break; default: returnValue = "reserved"; break; } } return returnValue; } /// <summary> /// This method returns the strip offsets EXIF property. /// </summary> private string StripOffsets() { return "Not implemented."; } /// <summary> /// This method returns the strip byte counts EXIF property. /// </summary> private string StripByteCounts() { return "Not implemented."; } /// <summary> /// This method returns the planar configuration EXIF property. /// </summary> private string PlanarConfiguration() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.PlanarConfiguration); //Translate the EXIF code into a readable value. if (data != null) { switch (data[0]) { case 1: returnValue = "chunky format"; break; case 2: returnValue = "planar format"; break; default: returnValue = "reserved"; break; } } return returnValue; } /// <summary> /// This method returns the YCbCr subsampling EXIF property. /// </summary> private string YCbCrSubSampling() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.YCbCrSubSampling); //Translate the EXIF code into a readable value. if (data != null) { switch (data[0]) { case 2: if (data[1] == 1) { returnValue = "YCbCr4:2:2"; } else { returnValue = "YCbCr4:2:0"; } break; default: returnValue = "reserved"; break; } } return returnValue; } /// <summary> /// This method returns the orientation EXIF property. /// </summary> private string Orientation() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.Orientation); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side."; break; case 2: returnValue = "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side."; break; case 3: returnValue = "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."; break; case 4: returnValue = "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."; break; case 5: returnValue = "The 0th row is at the visual left-hand side of the image, and the 0th column is the visual top."; break; case 6: returnValue = "The 0th row is at the visual right-hand side of the image, and the 0th column is the visual top."; break; case 7: returnValue = "The 0th row is at the visual right-hand side of the image, and the 0th column is the visual bottom."; break; case 8: returnValue = "The 0th row is at the visual left-hand side of the image, and the 0th column is the visual bottom."; break; default: returnValue = "Other"; break; } } return returnValue; } /// <summary> /// This method returns the resolution unit EXIF property. /// </summary> private string ResolutionUnit() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] resUnit = GetPropertyValue(Definitions.exifCode.ResolutionUnit); //Translate the EXIF code into a readable value. if (resUnit != null) { switch (resUnit[0]) { case 2: returnValue = "inches"; break; case 3: returnValue = "centimeters"; break; default: returnValue = "reserved"; break; } } return returnValue; } /// <summary> /// This method returns the white point EXIF property. /// </summary> private string WhitePoint() { string returnValue = "EXIF property not found."; EXIFRational[] data = ParsedRationalArray(Definitions.exifCode.WhitePoint); if (data.Length > 0) { returnValue = data[0].Denominator.ToString() + ", " + data[1].Denominator.ToString(); } return returnValue; } /// <summary> /// This method returns the primary chromaticities EXIF property. /// </summary> private string PrimaryChromaticities() { string returnValue = "EXIF property not found."; EXIFRational[] data = ParsedRationalArray(Definitions.exifCode.PrimaryChromaticities); if (data.Length > 0) { returnValue = data[0].Denominator.ToString() + ", " + data[1].Denominator.ToString() + ", " + data[2].Denominator.ToString() + ", " + data[3].Denominator.ToString() + ", " + data[4].Denominator.ToString() + ", " + data[5].Denominator.ToString(); } return returnValue; } /// <summary> /// This method returns the YCbCr coefficients EXIF property. /// </summary> private string YCbCrCoefficients() { string returnValue = "EXIF property not found."; EXIFRational[] data = ParsedRationalArray(Definitions.exifCode.YCbCrCoefficients); if (data.Length > 0) { returnValue = data[0].Denominator.ToString() + ", " + data[1].Denominator.ToString() + ", " + data[2].Denominator.ToString(); } return returnValue; } /// <summary> /// This method returns the YCbCr positioning EXIF property. /// </summary> private string YCbCrPositioning() { //Declare local variables. string returnValue = ""; byte[] data = GetPropertyValue(Definitions.exifCode.YCbCrPositioning); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "centered"; break; case 2: returnValue = "co-sited"; break; default: returnValue = "reserved"; break; } } else { returnValue = "EXIF property not found."; } return returnValue; } /// <summary> /// This method returns the reference black white EXIF property. /// </summary> private string ReferenceBlackWhite() { string returnValue = "EXIF property not found."; EXIFRational[] data = ParsedRationalArray(Definitions.exifCode.ReferenceBlackWhite); if (data.Length > 0) { returnValue = "[" + data[0].Denominator.ToString() + ", " + data[1].Denominator.ToString() + ", " + data[2].Denominator.ToString() + ", " + data[3].Denominator.ToString() + ", " + data[4].Denominator.ToString() + ", " + data[5].Denominator.ToString() + "]"; } return returnValue; } /// <summary> /// This method returns the exposure time EXIF property. /// </summary> private string ExposureTime() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational exposureTime = ParsedRational(Definitions.exifCode.ExposureTime); //Translate the EXIF code into a readable value. if (!exposureTime.Equals(null)) { if (exposureTime.Numerator == 0 && exposureTime.Denominator == 0) { returnValue = "N/A"; } else { returnValue = string.Format("{0}/{1} s", exposureTime.Numerator, exposureTime.Denominator); } } else { returnValue = "N/A"; } return returnValue; } /// <summary> /// This method returns the FNumber EXIF property. /// </summary> private string FNumber() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational fNumber = ParsedRational(Definitions.exifCode.FNumber); //Translate the EXIF code into a readable value. if (!fNumber.Equals(null)) { returnValue = string.Format("f{0}", (float)(fNumber.Numerator / fNumber.Denominator)); } return returnValue; } /// <summary> /// This method returns the exposure program EXIF property. /// </summary> private string ExposureProgram() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.ExposureProgram); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Not defined"; break; case 1: returnValue = "Manual"; break; case 2: returnValue = "Normal program"; break; case 3: returnValue = "Aperture priority"; break; case 4: returnValue = "Shutter priority"; break; case 5: returnValue = "Creative program (biased toward depth of field)"; break; case 6: returnValue = "Action program (biased toward fast shutter speed)"; break; case 7: returnValue = "Portrait mode (for closeup photos with the background out of focus)"; break; case 8: returnValue = "Landscape mode (for landscape photos with the background in focus)"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the components configuration EXIF property. /// </summary> private string ComponentsConfiguration() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.ComponentsConfiguration); switch (data[0]) { case 1: returnValue = "YCbCr"; break; case 4: returnValue = "RGB"; break; default: returnValue = "Reserved"; break; } return returnValue; } /// <summary> /// This method returns the compressed bits per pixel EXIF property. /// </summary> // This method needs to fixed to return the correct value. private string CompressedBitsPerPixel() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational cbpp = ParsedRational(Definitions.exifCode.CompressedBitsPerPixel); //Translate the EXIF code into a readable value. if (!cbpp.Equals(null)) { returnValue = string.Format("{0}/{1}", cbpp.Numerator, cbpp.Denominator); } return returnValue; } /// <summary> /// This method returns the aperture value EXIF property. /// </summary> private string ApertureValue() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational fNumber = ParsedRational(Definitions.exifCode.FNumber); //Translate the EXIF code into a readable value. if (!fNumber.Equals(null)) { double av = Math.Round(2 * Math.Log(((fNumber.Numerator / fNumber.Denominator)), 2.00)); returnValue = string.Format("f{0}", (double)av); } return returnValue; } /// <summary> /// This method returns the shutter speed value EXIF property. /// </summary> private string ShutterSpeedValue() { //Declare local variables. string returnValue = "EXIF property not found."; returnValue = ExposureTime(); return returnValue; } /// <summary> /// This method returns the subject distance EXIF property. /// </summary> private string SubjectDistance() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational sd = ParsedRational(Definitions.exifCode.SubjectDistance); //Translate the EXIF code into a readable value. if (!sd.Equals(null)) { returnValue = string.Format("{0}", sd.Numerator); } return returnValue; } /// <summary> /// This method returns the metering mode EXIF property. /// </summary> private string MeteringMode() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.MeteringMode); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Unknown"; break; case 1: returnValue = "Average"; break; case 2: returnValue = "CenterWeightedAverage"; break; case 3: returnValue = "Spot"; break; case 4: returnValue = "MultiSpot"; break; case 5: returnValue = "Pattern"; break; case 6: returnValue = "Partial"; break; case 255: returnValue = "Other"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the light source EXIF property. /// </summary> private string LightSource() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.LightSource); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "Daylight"; break; case 2: returnValue = "Fluorescent"; break; case 3: returnValue = "Tungsten (incandescent light)"; break; case 4: returnValue = "Flash"; break; case 9: returnValue = "Fine weather"; break; case 10: returnValue = "Cloudy weather"; break; case 11: returnValue = "Shade"; break; case 12: returnValue = "Daylight fluorescent (D 5700 - 7100K)"; break; case 13: returnValue = "Day white fluorescent (N 4600 - 5400K)"; break; case 14: returnValue = "Cool white fluorescent (W 3900 - 4500K)"; break; case 15: returnValue = "White fluorescent (WW 3200 - 3700K)"; break; case 17: returnValue = "Standard light A"; break; case 18: returnValue = "Standard light B"; break; case 19: returnValue = "Standard light C"; break; case 20: returnValue = "D55"; break; case 21: returnValue = "D65"; break; case 22: returnValue = "D75."; break; case 23: returnValue = "D50"; break; case 24: returnValue = "ISO studio tungsten"; break; case 255: returnValue = "other light source"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the flash EXIF property. /// </summary> private string Flash() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.Flash); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Flash did not fire."; break; case 1: returnValue = "Flash fired."; break; case 5: returnValue = "Strobe return light not detected."; break; case 7: returnValue = "Strobe return light detected."; break; case 9: returnValue = "Flash fired, compulsory flash mode."; break; case 13: returnValue = "Flash fired, compulsory flash mode, return light not detected."; break; case 15: returnValue = "Flash fired, compulsory flash mode, return light detected."; break; case 16: returnValue = "Flash did not fire, compulsory flash mode."; break; case 24: returnValue = "Flash did not fire, auto mode."; break; case 25: returnValue = "Flash fired, auto mode."; break; case 29: returnValue = "Flash fired, auto mode, return light not detected."; break; case 31: returnValue = "Flash fired, auto mode, return light detected."; break; case 32: returnValue = "No flash function."; break; case 65: returnValue = "Flash fired, red-eye reduction mode."; break; case 69: returnValue = "Flash fired, red-eye reduction mode, return light not detected."; break; case 71: returnValue = "Flash fired, red-eye reduction mode, return light detected."; break; case 73: returnValue = "Flash fired, compulsory flash mode, red-eye reduction mode."; break; case 77: returnValue = "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected."; break; case 79: returnValue = "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected."; break; case 89: returnValue = "Flash fired, auto mode, red-eye reduction mode."; break; case 93: returnValue = "Flash fired, auto mode, return light not detected, red-eye reduction mode."; break; case 95: returnValue = "Flash fired, auto mode, return light detected, red-eye reduction mode."; break; default: returnValue = "Not defined, reserved."; break; } } return returnValue; } /// <summary> /// This method returns the focal length EXIF property. /// </summary> private string FocalLength() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational focalLength = ParsedRational(Definitions.exifCode.FocalLength); //Translate the EXIF code into a readable value. if (!focalLength.Equals(null)) { if (focalLength.Numerator == 0 && focalLength.Denominator == 0) { returnValue = "N/A"; } else { returnValue = string.Format("{0:N0} mm", focalLength.Numerator * 1.0 / focalLength.Denominator); } } return returnValue; } /// <summary> /// This method returns the maker note EXIF property. /// </summary> private string MakerNote() { return "Not implemented."; } /// <summary> /// This method returns the color space EXIF property. /// </summary> private string ColorSpace() { //Declare local variables. string returnValue = "EXIF property not found."; byte[] data = GetPropertyValue(Definitions.exifCode.ColorSpace); //Translate the EXIF code into a readable value. if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "sRGB"; break; case 255: returnValue = "Uncalibrated"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the focal plane x resolution EXIF property. /// </summary> private string FocalPlaneXResolution() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational focalPlaneXRes = ParsedRational(Definitions.exifCode.FocalPlaneXResolution); //Translate the EXIF code into a readable value. if (!focalPlaneXRes.Equals(null)) { returnValue = string.Format("{0:N0} mm", (focalPlaneXRes.Numerator * 1.0 / focalPlaneXRes.Denominator)); } return returnValue; } /// <summary> /// This method returns the focal plane y resolution EXIF property. /// </summary> private string FocalPlaneYResolution() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational focalPlaneYRes = ParsedRational(Definitions.exifCode.FocalPlaneYResolution); //Translate the EXIF code into a readable value. if (!focalPlaneYRes.Equals(null)) { returnValue = string.Format("{0:N0} mm", focalPlaneYRes.Numerator * 1.0 / focalPlaneYRes.Denominator); } return returnValue; } /// <summary> /// This method returns the exposure index EXIF property. /// </summary> private string ExposureIndex() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational expIndex = ParsedRational(Definitions.exifCode.ExposureIndex); //Translate the EXIF code into a readable value. if (!expIndex.Equals(null)) { returnValue = string.Format("{0:N0} mm", expIndex.Numerator * 1.0 / expIndex.Denominator); } return returnValue; } /// <summary> /// This method returns the sensing method EXIF property. /// </summary> private string SensingMethod() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.SensingMethod); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "Not defined."; break; case 2: returnValue = "One-chip color area sensor."; break; case 3: returnValue = "Two-chip color area sensor."; break; case 4: returnValue = "Three-chip color area sensor."; break; case 5: returnValue = "Color sequential area sensor."; break; case 7: returnValue = "Trilinear sensor."; break; case 8: returnValue = "Color sequential linear sensor"; break; default: returnValue = "Reserved."; break; } } return returnValue; } /// <summary> /// This method returns the file source EXIF property. /// </summary> private string FileSource() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.FileSource); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 3: returnValue = "DSC"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the scene type EXIF property. /// </summary> private string SceneType() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.FileSource); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 1: returnValue = "A directly photographed image."; break; default: returnValue = "Reserved."; break; } } return returnValue; } /// <summary> /// This method returns the custom rendered EXIF property. /// </summary> private string CustomRendered() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.CustomRendered); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Normal process"; break; case 1: returnValue = "Custom process"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the exposure mode EXIF property. /// </summary> private string ExposureMode() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.ExposureMode); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Auto exposure"; break; case 1: returnValue = "Manual exposure"; break; case 2: returnValue = "Auto bracket"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the white balance EXIF property. /// </summary> private string WhiteBalance() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.WhiteBalance); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Auto white balance"; break; case 1: returnValue = "Manual white balance"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the focal length in 35mm film EXIF property. /// </summary> private string FocalLengthIn35mmFilm() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.FocalLengthIn35mmFilm); string returnValue = "EXIF property not found."; if (data.Length > 0) { if (data[0] == 0) { returnValue = "Unknown"; } else if (data[0].ToString().Trim() == "NaN") { returnValue = "N/A"; } else { returnValue = data[0].ToString() + "mm"; } } return returnValue; } /// <summary> /// This method returns the scene capture type EXIF property. /// </summary> private string SceneCaptureType() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.SceneCaptureType); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Standard"; break; case 1: returnValue = "Landscape"; break; case 2: returnValue = "Portrait"; break; case 3: returnValue = "Night scene"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the gain control EXIF property. /// </summary> private string GainControl() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.GainControl); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "None"; break; case 1: returnValue = "Low gain up"; break; case 2: returnValue = "High gain up"; break; case 3: returnValue = "Low gain down"; break; case 4: returnValue = "High gain down"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the contrast EXIF property. /// </summary> private string Contrast() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.Contrast); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Normal"; break; case 1: returnValue = "Soft"; break; case 2: returnValue = "Hard"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the saturation EXIF property. /// </summary> private string Saturation() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.Saturation); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Normal"; break; case 1: returnValue = "Low saturation"; break; case 2: returnValue = "High saturation"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the sharpness EXIF property. /// </summary> private string Sharpness() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.Sharpness); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Normal"; break; case 1: returnValue = "Soft"; break; case 2: returnValue = "Hard"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the subject distance range EXIF property. /// </summary> private string SubjectDistanceRange() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.SubjectDistanceRange); string returnValue = "EXIF property not found."; if (data.Length > 0) { switch (data[0]) { case 0: returnValue = "Unknown"; break; case 1: returnValue = "Macro"; break; case 2: returnValue = "Close view"; break; case 3: returnValue = "Distant view"; break; default: returnValue = "Reserved"; break; } } return returnValue; } /// <summary> /// This method returns the subject location EXIF property. /// </summary> private string SubjectLocation() { // Declare local variables. // Get the value for this EXIF property. byte[] data = GetPropertyValue(Definitions.exifCode.SubjectLocation); string returnValue = "EXIF property not found."; if (data.Length > 0) { returnValue = "(" + data[0].ToString() + ", " + data[1].ToString() + ")"; } return returnValue; } /// <summary> /// This method returns the digital zoom ratio EXIF property. /// </summary> private string DigitalZoomRatio() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational dzr = ParsedRational(Definitions.exifCode.DigitalZoomRatio); //Translate the EXIF code into a readable value. if (!dzr.Equals(null)) { returnValue = dzr.Numerator.ToString() + ":" + dzr.Denominator.ToString(); } return returnValue; } /// <summary> /// This method returns the brightness value EXIF property. /// </summary> private string BrightnessValue() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational data = ParsedRational(Definitions.exifCode.DigitalZoomRatio); //Translate the EXIF code into a readable value. if (!data.Equals(null)) { if ((long)data.Numerator >= Int32.MaxValue) { returnValue = "Unknown"; } else { returnValue = Math.Log(data.Numerator / data.Denominator, 2.0).ToString(); } } return returnValue; } /// <summary> /// This method returns the max aperture value EXIF property. /// </summary> private string MaxApertureValue() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational data = ParsedRational(Definitions.exifCode.MaxApertureValue); //Translate the EXIF code into a readable value. if (!data.Equals(null)) { returnValue = string.Format("f{0}", (double)(data.Numerator / data.Denominator)); } return returnValue; } /// <summary> /// This method returns the exposure bias value EXIF property. /// </summary> private string ExposureBiasValue() { //Declare local variables. string returnValue = "EXIF property not found."; EXIFRational data = ParsedRational(Definitions.exifCode.ExposureBiasValue); //Translate the EXIF code into a readable value. if (!data.Equals(null)) { returnValue = string.Format("f{0}", (double)(data.Numerator / data.Denominator)); } return returnValue; } #endregion #region -- Private helper functions -- // Private helper functions. /// <summary> /// This method retrieves the data from the propery items collection. /// </summary> private byte[] GetPropertyValue(Definitions.exifCode exifCode) { return _picture.GetPropertyItem((int)exifCode).Value; } /// <summary> /// This method returns string EXIF data. /// </summary> private string ParsedString(Definitions.exifCode exifCode) { // Declare local variables. // Retrieve the data for this EXIF property. byte[] data = GetPropertyValue(exifCode); // Holds the return value. string parsed = ""; // If there's data, go ahead and parse it. if (data.Length > 1) { // Allocate some memory. IntPtr h = Marshal.AllocHGlobal(data.Length); int i = 0; foreach (byte b in data) { Marshal.WriteByte(h, i, b); i++; } parsed = Marshal.PtrToStringAnsi(h); Marshal.FreeHGlobal(h); } return parsed; } /// <summary> /// This method returns rational EXIF data. /// </summary> private EXIFRational ParsedRational(Definitions.exifCode exifCode) { // Declare local variables. // Retrieve the data for this EXIF property. byte[] data = GetPropertyValue(exifCode); // Parse the data. EXIFRational parsed = new EXIFRational(data); return parsed; } /// <summary> /// This method returns an array of rational EXIF data. /// </summary> private EXIFRational[] ParsedRationalArray(Definitions.exifCode exifCode) { // Declare local variables. // Retrieve the data for this EXIF property. byte[] data = GetPropertyValue(exifCode); // Holds the return value. EXIFRational[] parsed = null; int arraySize = (data.Length / 8); if (arraySize > 0) { parsed = new EXIFRational[arraySize]; for (int i = 0; i < arraySize; i++) { parsed[i] = new EXIFRational(data, i * 8); } } return parsed; } /// <summary> /// This method returns date/time EXIF data. /// </summary> private DateTime ParsedDate(Definitions.exifCode exifCode) { // Declare local variables. // Create a new date object. DateTime ret = new DateTime(1900, 1, 1, 0, 0, 0); // Parse the data. string date = ParsedString(exifCode); // Format the data. if (date.Length >= 19) {
### 调试与修复方法 #### 1. **理解等效焦距的计算逻辑** 在多摄系统中,等效焦距的计算通常基于传感器尺寸与镜头焦距的换算关系,并以35mm全画幅作为标准。不同拍照模式下,系统可能采用不同的传感器区域(如主摄与副摄的切换),导致等效焦距的计算存在差异。例如,专业tele3.1x模式下,系统可能使用副摄的物理焦距,并结合传感器尺寸进行换算,最终显示的等效焦距可能因裁剪比例或缩放因子的调整而与理论值存在偏差。因此,在调试时,需要明确不同模式下使用的传感器尺寸和镜头焦距,并确保等效焦距的计算公式一致。 #### 2. **检查不同模式下的图像裁剪区域** 在多摄系统中,不同拍照模式(如wide、tele)可能使用不同的图像裁剪区域。例如,专业tele3.1x模式下,系统可能从主摄或副摄的全分辨率图像中裁剪出一个较小的区域,并通过插值放大来实现目标焦距效果。这种裁剪和插值过程会影响最终显示的等效焦距。调试时,应检查不同模式下使用的裁剪比例,并确保裁剪区域与等效焦距的计算逻辑一致。以下是一个示例代码,用于计算裁剪比例对等效焦距的影响: ```python def calculate_equivalent_focal_length(actual_focal_length, sensor_diagonal, full_frame_diagonal=43.27): """ 计算等效焦距 :param actual_focal_length: 实际焦距 :param sensor_diagonal: 传感器对角线长度 :param full_frame_diagonal: 全画幅传感器对角线长度(默认为43.27mm) :return: 等效焦距 """ return (actual_focal_length / sensor_diagonal) * full_frame_diagonal # 示例:计算副摄tele3.1x模式下的等效焦距 actual_focal_length = 24 # 副摄的实际焦距 sensor_diagonal = 26.82 # 副摄传感器对角线长度 equivalent_focal_length = calculate_equivalent_focal_length(actual_focal_length, sensor_diagonal) print(f"等效焦距: {equivalent_focal_length:.2f}mm") ``` #### 3. **验证ISP处理与图像预览的缩放策略** 图像信号处理器(ISP)在处理图像时,会根据当前拍照模式调整图像的预览缩放比例。例如,在专业模式下,ISP可能对图像进行轻微裁剪以优化画质或色彩表现,从而导致最终显示的等效焦距与预期略有不同。调试时,应检查ISP的缩放策略,并确保不同模式下使用的缩放比例一致。此外,不同平台(如Qualcomm、MTK)在ISP实现路径和LUT(查找表)校准策略上存在差异,也可能影响焦距的显示一致性。 #### 4. **校准摄像头参数** 在摄像头模组出厂前,通常需要进行镜头阴影校正(LSC)、焦距标定等步骤。若校准参数未精确同步或存在误差,可能导致系统在不同模式下读取的焦距值不一致。特别是在多摄协同变焦时,若主摄与副摄的焦距参数未完全对齐,也可能造成等效焦距的显示偏差。调试时,应使用厂商提供的校准工具重新校准摄像头模组,确保各镜头的焦距参数一致,并更新到系统配置中。 #### 5. **更新相机固件与ISP配置** 联系模组厂商获取最新的ISP配置文件(如LUT表、LSC参数等),确保图像处理流程中焦距计算逻辑的准确性。此外,软件层面对等效焦距的计算逻辑也应进行统一,确保不同拍照模式下使用一致的换算基准(如统一使用35mm等效焦距计算公式)。 #### 6. **软件层面对齐策略** 在应用层或HAL层对等效焦距的计算逻辑进行统一,确保不同拍照模式下使用一致的换算基准。例如,可以在应用层定义一个统一的焦距换算函数,并在所有拍照模式下调用该函数进行等效焦距计算。以下是一个示例代码,用于统一等效焦距的计算逻辑: ```python class CameraSystem: def __init__(self): self.full_frame_diagonal = 43.27 # 全画幅传感器对角线长度 def calculate_equivalent_focal_length(self, actual_focal_length, sensor_diagonal): """ 计算等效焦距 :param actual_focal_length: 实际焦距 :param sensor_diagonal: 传感器对角线长度 :return: 等效焦距 """ return (actual_focal_length / sensor_diagonal) * self.full_frame_diagonal # 示例:在不同模式下调用统一的等效焦距计算函数 camera_system = CameraSystem() # wide模式 actual_focal_length_wide = 18 # wide模式下的实际焦距 sensor_diagonal_wide = 26.82 # wide模式下的传感器对角线长度 equivalent_focal_length_wide = camera_system.calculate_equivalent_focal_length(actual_focal_length_wide, sensor_diagonal_wide) print(f"wide模式下的等效焦距: {equivalent_focal_length_wide:.2f}mm") # tele3.1x模式 actual_focal_length_tele = 55 # tele3.1x模式下的实际焦距 sensor_diagonal_tele = 26.82 # tele3.1x模式下的传感器对角线长度 equivalent_focal_length_tele = camera_system.calculate_equivalent_focal_length(actual_focal_length_tele, sensor_diagonal_tele) print(f"tele3.1x模式下的等效焦距: {equivalent_focal_length_tele:.2f}mm") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值