HIGH高频H2(11-20)

HIGH.10 合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

 

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
 

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出:[1,2,2,3,5,6]
 

提示:

-10^9 <= nums1[i], nums2[i] <= 10^9
nums1.length == m + n
nums2.length == n

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p = m-- + n-- - 1;
        while (m >= 0 && n >= 0) {
            nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];
        }
        
        while (n >= 0) {
            nums1[p--] = nums2[n--];
        }
    }

HIGH.11 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
限制:

0 <= 链表长度 <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

迭代

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(-1), pre = dummyHead;
        while (l1 != null && l2 != null) {
            if (l1.val <= l2.val) {
                pre.next = l1;
                pre = pre.next;
                l1 = l1.next;
            } else {
                pre.next = l2;
                pre = pre.next;
                l2 = l2.next;
            }
        }
        if (l1 != null) {
            pre.next = l1;
        }
        if (l2 != null) {
            pre.next = l2;
        }

        return dummyHead.next;
    }
}

递归

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        if (l2 == null) {
            return l1;
        }
        if (l1.val <= l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

HIGH.12 合并K 个排序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]
示例 3:

输入:lists = [[]]
输出:[]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路巨简单,难得一次都不用调试!!!循环直接搞定,什么分治大法我不懂!

用容量为K的最小堆优先队列,把链表的头结点都放进去,然后出队当前优先队列中最小的,挂上链表,,然后让出队的那个节点的下一个入队,再出队当前优先队列中最小的,直到优先队列为空。

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {

        if (lists.length == 0) {
            return null;
        }

        ListNode dummyHead = new ListNode(0);
        ListNode curr = dummyHead;
        PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });

        for (ListNode list : lists) {
            if (list == null) {
                continue;
            }
            pq.add(list);
        }

        while (!pq.isEmpty()) {
            ListNode nextNode = pq.poll();
            curr.next = nextNode;
            curr = curr.next;
            if (nextNode.next != null) {
                pq.add(nextNode.next);
            }
        }
        return dummyHead.next;
    }
}

HIGH.13 买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

 

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路还是挺清晰的,还是DP思想:

记录【今天之前买入的最小值】
计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】
比较【每天的最大获利】,取最大值即可

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length <= 1)
            return 0;
        int min = prices[0], max = 0;
        for(int i = 1; i < prices.length; i++) {
            max = Math.max(max, prices[i] - min);
            min = Math.min(min, prices[i]);
        }
        return max;
    }
}

HIGH.14 买卖股票的最佳时机II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

 

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

算法题(×) 脑筋急转弯题( √ )

扫描一遍 只要后一天比前一天大 就把这两天的差值加一下

class Solution {
    public int maxProfit(int[] prices) {
        int ans=0;
        for(int i=1;i<=prices.length-1;i++)
        {
            if(prices[i]>prices[i-1])
            {
                ans+=prices[i]-prices[i-1];
            }
        }
        return ans;
    }
}

HIGH.15 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        int sum = 0;
        for (int num : nums) {
            if (sum > 0)
                sum += num;
            else
                sum = num;
            res = Math.max(res, sum);
        }
        return res;
    }
}

HIGH.16 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
 

示例:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.
 

提示:

pop、top 和 getMin 操作总是在 非空栈 上调用。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class MinStack {
    private Node head;
    
    public void push(int x) {
        if(head == null) 
            head = new Node(x, x);
        else 
            head = new Node(x, Math.min(x, head.min), head);
    }

    public void pop() {
        head = head.next;
    }

    public int top() {
        return head.val;
    }

    public int getMin() {
        return head.min;
    }
    
    private class Node {
        int val;
        int min;
        Node next;
        
        private Node(int val, int min) {
            this(val, min, null);
        }
        
        private Node(int val, int min, Node next) {
            this.val = val;
            this.min = min;
            this.next = next;
        }
    }
}

HIGH.17 LRU 缓存机制

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
 

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

 

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4
 

提示:

1 <= capacity <= 3000
0 <= key <= 3000
0 <= value <= 104
最多调用 3 * 104 次 get 和 put

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class LRUCache {

        private int cap;
	private Map<Integer, Integer> map = new LinkedHashMap<>();  // 保持插入顺序

	public LRUCache(int capacity) {
		this.cap = capacity;
	}

	public int get(int key) {
		if (map.keySet().contains(key)) {
			int value = map.get(key);
			map.remove(key);
                       // 保证每次查询后,都在末尾
			map.put(key, value);
			return value;
		}
		return -1;
	}

	public void put(int key, int value) {
		if (map.keySet().contains(key)) {
			map.remove(key);
		} else if (map.size() == cap) {
			Iterator<Map.E***y<Integer, Integer>> iterator = map.e***ySet().iterator();
			iterator.next();
			iterator.remove();

			// int firstKey = map.e***ySet().iterator().next().getValue();
			// map.remove(firstKey);
		}
		map.put(key, value);
	}
}

HIGH.18 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

 

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000
 

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这道题让我们求两个有序数组的中位数,而且限制了时间复杂度为O(log (m+n)),看到这个时间复杂度,自然而然的想到了应该使用二分查找法来求解。那么回顾一下中位数的定义,如果某个有序数组长度是奇数,那么其中位数就是最中间那个,如果是偶数,那么就是最中间两个数字的平均值。这里对于两个有序数组也是一样的,假设两个有序数组的长度分别为m和n,由于两个数组长度之和 m+n 的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。为了简化代码,不分情况讨论,我们使用一个小trick,我们分别找第 (m+n+1) / 2 个,和 (m+n+2) / 2 个,然后求其平均值即可,这对奇偶数均适用。加入 m+n 为奇数的话,那么其实 (m+n+1) / 2 和 (m+n+2) / 2 的值相等,相当于两个相同的数字相加再除以2,还是其本身。

这里我们需要定义一个函数来在两个有序数组中找到第K个元素,下面重点来看如何实现找到第K个元素。首先,为了避免产生新的数组从而增加时间复杂度,我们使用两个变量i和j分别来标记数组nums1和nums2的起始位置。然后来处理一些边界问题,比如当某一个数组的起始位置大于等于其数组长度时,说明其所有数字均已经被淘汰了,相当于一个空数组了,那么实际上就变成了在另一个数组中找数字,直接就可以找出来了。还有就是如果K=1的话,那么我们只要比较nums1和nums2的起始位置i和j上的数字就可以了。难点就在于一般的情况怎么处理?因为我们需要在两个有序数组中找到第K个元素,为了加快搜索的速度,我们要使用二分法,对K二分,意思是我们需要分别在nums1和nums2中查找第K/2个元素,注意这里由于两个数组的长度不定,所以有可能某个数组没有第K/2个数字,所以我们需要先检查一下,数组中到底存不存在第K/2个数字,如果存在就取出来,否则就赋值上一个整型最大值。如果某个数组没有第K/2个数字,那么我们就淘汰另一个数字的前K/2个数字即可。有没有可能两个数组都不存在第K/2个数字呢,这道题里是不可能的,因为我们的K不是任意给的,而是给的m+n的中间值,所以必定至少会有一个数组是存在第K/2个数字的。最后就是二分法的核心啦,比较这两个数组的第K/2小的数字midVal1和midVal2的大小,如果第一个数组的第K/2个数字小的话,那么说明我们要找的数字肯定不在nums1中的前K/2个数字,所以我们可以将其淘汰,将nums1的起始位置向后移动K/2个,并且此时的K也自减去K/2,调用递归。反之,我们淘汰nums2中的前K/2个数字,并将nums2的起始位置向后移动K/2个,并且此时的K也自减去K/2,调用递归即可。

class Solution {
  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int left = (m + n + 1) / 2;
        int right = (m + n + 2) / 2;
        return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
    }
    //i: nums1的起始位置 j: nums2的起始位置
    public int findKth(int[] nums1, int i, int[] nums2, int j, int k){
        if( i >= nums1.length) return nums2[j + k - 1];//nums1为空数组
        if( j >= nums2.length) return nums1[i + k - 1];//nums2为空数组
        if(k == 1){
            return Math.min(nums1[i], nums2[j]);
        }
        int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
        int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
        if(midVal1 < midVal2){
            return findKth(nums1, i + k / 2, nums2, j , k - k / 2);
        }else{
            return findKth(nums1, i, nums2, j + k / 2 , k - k / 2);
        }        
    }
}

HIGH.19 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:

输入: "cbbd"
输出: "bb"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
//         保存起始位置,测试了用数组似乎能比全局变量稍快一点
        int[] range = new int[2];
        char[] str = s.toCharArray();
        for (int i = 0; i < s.length(); i++) {
//             把回文看成中间的部分全是同一字符,左右部分相对称
//             找到下一个与当前字符不同的字符
            i = findLongest(str, i, range);
        }
        return s.substring(range[0], range[1] + 1);
    }
    
    public static int findLongest(char[] str, int low, int[] range) {
//         查找中间部分
        int high = low;
        while (high < str.length - 1 && str[high + 1] == str[low]) {
            high++;
        }
//         定位中间部分的最后一个字符
        int ans = high;
//         从中间向左右扩散
        while (low > 0 && high < str.length - 1 && str[low - 1] == str[high + 1]) {
            low--;
            high++;
        }
//         记录最大长度
        if (high - low > range[1] - range[0]) {
            range[0] = low;
            range[1] = high;
        }
        return ans;
    }
}

HIGH.20 合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

 

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
 

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出:[1,2,2,3,5,6]
 

提示:

-10^9 <= nums1[i], nums2[i] <= 10^9
nums1.length == m + n
nums2.length == n

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p = m-- + n-- - 1;
        while (m >= 0 && n >= 0) {
            nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];
        }
        
        while (n >= 0) {
            nums1[p--] = nums2[n--];
        }
    }
}

 

 

 

 

 

 

<think> 我们正在讨论图像融合中的低频和高频部分的融合方法。根据用户引用的资料,特别是引用[1]和[2],他们提到了基于小波变换的图像融合方法,其中对低频系数和高频系数采用不同的融合策略。 然而,用户之前的问题是关于NSST滤波器的原理,现在转向图像融合中分解后的低频和高频部分的融合方法。因此,我们需要结合小波变换(用户引用中提到的)和NSST(之前讨论的)来回答。 图像融合通常包括以下步骤: 1. 对每幅源图像进行多尺度分解(如小波变换、NSST等),得到低频子带和高频子带。 2. 对低频子带和高频子带分别采用不同的融合规则。 3. 对融合后的低频和高频子带进行重构,得到融合图像。 由于用户引用的资料主要涉及小波变换,但之前的问题是关于NSST,因此我们可以先介绍一般性的融合方法(小波变换),然后扩展到NSST。 低频部分通常代表图像的整体轮廓和光照信息,高频部分则代表细节(如边缘、纹理)。融合低频和高频部分的方法有以下几种常见策略: 一、低频系数的融合规则 1. 加权平均法:对两幅图像的低频系数进行加权平均,权值可以相等(简单平均)或根据图像特性调整(如基于清晰度、能量等)。 $$ L_f = w_1 \cdot L_1 + w_2 \cdot L_2 $$ 其中$w_1 + w_2 = 1$,常用的权值是0.5(平均)[^1]。 2. 选择最大法:选择两幅图像中绝对值最大的低频系数。 $$ L_f = \begin{cases} L_1 & \text{if } |L_1| \geq |L_2| \\ L_2 & \text{otherwise} \end{cases} $$ 3. 基于清晰度的方法:计算低频子带块的清晰度(如空间频率、梯度能量等),选择清晰度大的那个图像的低频系数[^2]。 二、高频系数的融合规则 1. 绝对值取大法:在对应位置,比较两幅图像高频系数的绝对值,取较大者。 $$ H_f = \begin{cases} H_1 & \text{if } |H_1| \geq |H_2| \\ H_2 & \text{otherwise} \end{cases} $$ 这种方法能保留显著的边缘和纹理[^1][^2]。 2. 区域能量法:计算以当前系数为中心的局部窗口内的能量(如平方和),选择能量大的那个图像的高频系数。 3. 加权法:根据一定规则(如区域清晰度)进行加权融合。 注意:在NSST分解中,由于有多个方向子带,高频融合策略可以针对每个方向子带独立进行。 三、NSST与小波融合的异同 虽然小波变换和NSST都是多尺度分解,但NSST具有更好的方向选择性(多个方向子带),因此在融合高频部分时,可以更精细地提取方向特征。融合规则类似,但NSST在每个尺度每个方向上都进行融合。 四、示例流程(以两幅源图像A、B融合为例) 1. 对图像A和图像B分别进行NSST分解,得到低频子带$L_A, L_B$和各尺度各方向的高频子带$H_{A,j,k}, H_{B,j,k}$(j为尺度,k为方向)。 2. 低频融合:采用加权平均法(或选择最大法、基于清晰度的方法等)得到融合后的低频$L_f$。 3. 高频融合:对每个尺度j和每个方向k,采用绝对值取大法(或区域能量法等)得到融合后的高频$H_{f,j,k}$。 4. 将融合后的低频$L_f$和高频$H_{f,j,k}$进行NSST逆变换,得到融合图像。 五、Matlab示例(伪代码) 由于引用[2][^2]提到Matlab源码,这里给出融合部分的伪代码: ```matlab % 假设已经得到两幅图像A和B的NSST分解 % 低频部分:LA, LB % 高频部分:HA, HB(每个尺度、方向上的子带) % 低频融合规则:加权平均 w = 0.5; L_fused = w * LA + (1-w) * LB; % 高频融合规则:绝对值取大 for scale = 1:num_scales for dir = 1:num_directions(scale) % 不同尺度的方向数可能不同 % 取出当前尺度和方向的子带 H1 = HA{scale}{dir}; H2 = HB{scale}{dir}; % 创建融合后的高频子带 H_fused{scale}{dir} = zeros(size(H1)); % 逐点比较 idx = abs(H1) >= abs(H2); H_fused{scale}{dir}(idx) = H1(idx); H_fused{scale}{dir}(~idx) = H2(~idx); end end % 然后进行NSST逆变换得到融合图像 fused_image = insst(L_fused, H_fused); ``` 六、注意事项 1. 在实际应用中,加权平均的低频融合可能导致对比度下降,因此有时采用其他方法(如基于清晰度的选择)来保持对比度[^2]。 2. 高频融合的绝对值取大法可能会引入噪声,因此有时采用区域窗口(如3x3)计算局部能量,然后选择整个窗口能量大的那个图像的高频系数。 七、引用说明 根据用户提供的引用: [^1] 提到低频系数加权和高频系数取绝对值最大值,这与上述方法一致。 [^2] 提到将图像分块进行融合,避免整幅图像变换的冗余,但我们的示例是针对整个子带进行的。实际中也可以分块进行融合(如将子带分块,再分别融合)。 因此,上述融合方法有文献支持。 现在,我们根据要求生成相关问题。 </think> ### 图像融合中低频与高频部分的融合方法 在图像融合任务中(如多聚焦图像融合、遥感图像融合等),通过多尺度分解(小波变换/NSST)后,需对低频和高频子带采用不同的融合策略。以下是核心方法及数学表达: --- ### 一、低频子带融合(表征光照/轮廓信息) 低频分量反映图像的整体结构和光照特征,常用融合规则: 1. **加权平均法** 对两幅源图像的低频系数$L_1, L_2$进行加权: $$ L_f = w \cdot L_1 + (1-w) \cdot L_2 \quad (0 \leq w \leq 1) $$ 其中$w$可基于图像清晰度动态调整[^1][^2]。 > *示例*:清晰图像权重$w$更高,避免模糊信息干扰全局亮度 2. **区域能量最大化** 计算局部窗口$W$(如3×3)的能量: $$ E_i(x,y) = \sum_{(m,n) \in W} |L_i(x+m,y+n)|^2 \quad (i=1,2) $$ 选择能量更大的低频系数: $$ L_f = \begin{cases} L_1 & \text{if } E_1 > E_2 \\ L_2 & \text{otherwise} \end{cases} $$ 此法保留更丰富的结构信息[^2][^3]. --- ### 二、高频子带融合(表征边缘/纹理信息) 高频分量包含细节特征,需保留显著边缘: 1. **绝对值取大法** 直接比较系数绝对值: $$ H_f = \begin{cases} H_1 & \text{if } |H_1| \geq |H_2| \\ H_2 & \text{otherwise} \end{cases} $$ 简单高效,但可能放大噪声[^1][^3]。 2. **局部方差决策** 计算窗口$W$内方差: $$ \sigma_i^2 = \frac{1}{N} \sum_{(m,n) \in W} \left( H_i(x+m,y+n) - \mu_i \right)^2 $$ 选择方差更大的系数(方差大表示细节丰富): $$ H_f = \begin{cases} H_1 & \text{if } \sigma_1^2 > \sigma_2^2 \\ H_2 & \text{otherwise} \end{cases} $$ 此法提升边缘清晰度[^2][^3]. --- ### 三、NSST特有的方向子带融合 在NSST分解中,高频子带包含多方向分量$H_{j,k}$($j$=尺度, $k$=方向),需**分层处理**: 1. **方向显著性融合** 对每个方向$k$独立执行: $$ H_{f,j,k} = \arg\max_{H \in \{H_{1,j,k}, H_{2,j,k}\}} \left( \text{局部梯度强度} \right) $$ 2. **跨方向一致性校验** 引入相邻方向约束: $$ H_{f,j,k} = \begin{cases} H_{1,j,k} & \text{if } \sum_{k' \in N(k)} |H_{1,j,k'}| > \sum_{k' \in N(k)} |H_{2,j,k'}| \\ H_{2,j,k} & \text{otherwise} \end{cases} $$ 其中$N(k)$是$k$的邻域方向,增强几何连续性[^3]. --- ### 四、完整融合流程 以两幅源图像$I_1, I_2$为例: ```mermaid graph TD A[I1] --> NSST1[NSST分解] B[I2] --> NSST2[NSST分解] NSST1 --> L1[低频子带] & H1[高频方向子带] NSST2 --> L2[低频子带] & H2[高频方向子带] L1 & L2 --> F_L[低频融合规则] --> L_f H1 & H2 --> F_H[高频融合规则] --> H_f L_f & H_f --> INSST[NSST逆变换] --> F[融合图像] ``` > **关键点**: > - 低频融合侧重**稳定性**(避免光照突变) > - 高频融合侧重**敏感性**(保留显著边缘) > - NSST方向子带需**独立处理+方向一致性约束**[^3] --- ### 五、Matlab实现示例(低频加权+高频取大) ```matlab % 假设已获得NSST分解结果:low1, low2 (低频), high1, high2 (高频方向子带) w = 0.6; % 清晰图像I1的权重 % 低频融合(加权平均) fused_low = w * low1 + (1-w) * low2; % 高频融合(绝对值取大) fused_high = cell(size(high1)); for j = 1:length(high1) % 遍历尺度 for k = 1:length(high1{j}) % 遍历方向 mask = abs(high1{j}{k}) >= abs(high2{j}{k}); fused_high{j}{k} = mask .* high1{j}{k} + ~mask .* high2{j}{k}; end end % 重构融合图像 fused_img = insst(fused_low, fused_high); % NSST逆变换 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值