summaryrefslogtreecommitdiff
path: root/src/ipa/ipu3/algorithms/tone_mapping.cpp
blob: 160338c139448cc9a0bc1fe2400c335a96f68f73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2021, Google inc.
 *
 * IPU3 ToneMapping and Gamma control
 */

#include "tone_mapping.h"

#include <cmath>
#include <string.h>

/**
 * \file tone_mapping.h
 */

namespace libcamera {

namespace ipa::ipu3::algorithms {

/**
 * \class ToneMapping
 * \brief A class to handle tone mapping based on gamma
 *
 * This algorithm improves the image dynamic using a look-up table which is
 * generated based on a gamma parameter.
 */

ToneMapping::ToneMapping()
	: gamma_(1.0)
{
}

/**
 * \brief Configure the tone mapping given a configInfo
 * \param[in] context The shared IPA context
 * \param[in] configInfo The IPA configuration data
 *
 * \return 0
 */
int ToneMapping::configure(IPAContext &context,
			   [[maybe_unused]] const IPAConfigInfo &configInfo)
{
	/* Initialise tone mapping gamma value. */
	context.activeState.toneMapping.gamma = 0.0;

	return 0;
}

/**
 * \brief Fill in the parameter structure, and enable gamma control
 * \param[in] context The shared IPA context
 * \param[in] frame The frame context sequence number
 * \param[in] frameContext The FrameContext for this frame
 * \param[out] params The IPU3 parameters
 *
 * Populate the IPU3 parameter structure with our tone mapping look up table and
 * enable the gamma control module in the processing blocks.
 */
void ToneMapping::prepare([[maybe_unused]] IPAContext &context,
			  [[maybe_unused]] const uint32_t frame,
			  [[maybe_unused]] IPAFrameContext &frameContext,
			  ipu3_uapi_params *params)
{
	/* Copy the calculated LUT into the parameters buffer. */
	memcpy(params->acc_param.gamma.gc_lut.lut,
	       context.activeState.toneMapping.gammaCorrection.lut,
	       IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES *
	       sizeof(params->acc_param.gamma.gc_lut.lut[0]));

	/* Enable the custom gamma table. */
	params->use.acc_gamma = 1;
	params->acc_param.gamma.gc_ctrl.enable = 1;
}

/**
 * \brief Calculate the tone mapping look up table
 * \param[in] context The shared IPA context
 * \param[in] frame The current frame sequence number
 * \param[in] frameContext The current frame context
 * \param[in] stats The IPU3 statistics and ISP results
 * \param[out] metadata Metadata for the frame, to be filled by the algorithm
 *
 * The tone mapping look up table is generated as an inverse power curve from
 * our gamma setting.
 */
void ToneMapping::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,
			  [[maybe_unused]] IPAFrameContext &frameContext,
			  [[maybe_unused]] const ipu3_uapi_stats_3a *stats,
			  [[maybe_unused]] ControlList &metadata)
{
	/*
	 * Hardcode gamma to 1.1 as a default for now.
	 *
	 * \todo Expose gamma control setting through the libcamera control API
	 */
	gamma_ = 1.1;

	if (context.activeState.toneMapping.gamma == gamma_)
		return;

	struct ipu3_uapi_gamma_corr_lut &lut =
		context.activeState.toneMapping.gammaCorrection;

	for (uint32_t i = 0; i < std::size(lut.lut); i++) {
		double j = static_cast<double>(i) / (std::size(lut.lut) - 1);
		double gamma = std::pow(j, 1.0 / gamma_);

		/* The output value is expressed on 13 bits. */
		lut.lut[i] = gamma * 8191;
	}

	context.activeState.toneMapping.gamma = gamma_;
}

REGISTER_IPA_ALGORITHM(ToneMapping, "ToneMapping")

} /* namespace ipa::ipu3::algorithms */

} /* namespace libcamera */
class="hl opt">), formats::R8 }, /* Bayer formats. */ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), formats::SBGGR8 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), formats::SGBRG8 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), formats::SGRBG8 }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), formats::SRGGB8 }, { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), formats::SBGGR10 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), formats::SGBRG10 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), formats::SGRBG10 }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), formats::SRGGB10 }, { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), formats::SBGGR10_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), formats::SGBRG10_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), formats::SGRBG10_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), formats::SRGGB10_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), formats::SBGGR12 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), formats::SGBRG12 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), formats::SGRBG12 }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), formats::SRGGB12 }, { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), formats::SBGGR12_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), formats::SGBRG12_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), formats::SGRBG12_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), formats::SRGGB12_CSI2P }, { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), formats::SBGGR16 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), formats::SGBRG16 }, { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), formats::SGRBG16 }, { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), formats::SRGGB16 }, /* Compressed formats. */ { V4L2PixelFormat(V4L2_PIX_FMT_MJPEG), formats::MJPEG }, }; } /* namespace */ /** * \fn V4L2PixelFormat::V4L2PixelFormat() * \brief Construct a V4L2PixelFormat with an invalid format * * V4L2PixelFormat instances constructed with the default constructor are * invalid, calling the isValid() function returns false. */ /** * \fn V4L2PixelFormat::V4L2PixelFormat(uint32_t fourcc) * \brief Construct a V4L2PixelFormat from a FourCC value * \param[in] fourcc The pixel format FourCC numerical value */ /** * \fn bool V4L2PixelFormat::isValid() const * \brief Check if the pixel format is valid * * V4L2PixelFormat instances constructed with the default constructor are * invalid. Instances constructed with a FourCC defined in the V4L2 API are * valid. The behaviour is undefined otherwise. * * \return True if the pixel format is valid, false otherwise */ /** * \fn uint32_t V4L2PixelFormat::fourcc() const * \brief Retrieve the pixel format FourCC numerical value * \return The pixel format FourCC numerical value */ /** * \fn V4L2PixelFormat::operator uint32_t() const * \brief Convert to the pixel format FourCC numerical value * \return The pixel format FourCC numerical value */ /** * \brief Assemble and return a string describing the pixel format * \return A string describing the pixel format */ std::string V4L2PixelFormat::toString() const { if (fourcc_ == 0) return "<INVALID>"; char ss[8] = { static_cast<char>(fourcc_ & 0x7f), static_cast<char>((fourcc_ >> 8) & 0x7f), static_cast<char>((fourcc_ >> 16) & 0x7f), static_cast<char>((fourcc_ >> 24) & 0x7f) }; for (unsigned int i = 0; i < 4; i++) { if (!isprint(ss[i])) ss[i] = '.'; } if (fourcc_ & (1 << 31)) strcat(ss, "-BE"); return ss; } /** * \brief Convert the V4L2 pixel format to the corresponding PixelFormat * \return The PixelFormat corresponding to the V4L2 pixel format */ PixelFormat V4L2PixelFormat::toPixelFormat() const { const auto iter = vpf2pf.find(*this); if (iter == vpf2pf.end()) { LOG(V4L2, Warning) << "Unsupported V4L2 pixel format " << toString(); return PixelFormat(); } return iter->second; } /** * \brief Convert \a pixelFormat to its corresponding V4L2PixelFormat * \param[in] pixelFormat The PixelFormat to convert * \param[in] multiplanar V4L2 Multiplanar API support flag * * Multiple V4L2 formats may exist for one PixelFormat when the format uses * multiple planes, as V4L2 defines separate 4CCs for contiguous and separate * planes formats. Set the \a multiplanar parameter to false to select a format * with contiguous planes, or to true to select a format with non-contiguous * planes. * * \return The V4L2PixelFormat corresponding to \a pixelFormat */ V4L2PixelFormat V4L2PixelFormat::fromPixelFormat(const PixelFormat &pixelFormat, [[maybe_unused]] bool multiplanar) { const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat); if (!info.isValid()) return V4L2PixelFormat(); return info.v4l2Format; } } /* namespace libcamera */